diff options
Diffstat (limited to 'drivers/gpu/drm/rockchip')
-rw-r--r-- | drivers/gpu/drm/rockchip/Kconfig | 25 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 104 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 48 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_rgb.c | 173 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_rgb.h | 33 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 215 | ||||
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_vop_reg.h | 99 |
10 files changed, 640 insertions, 61 deletions
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 0ccc76217ee4..26438d45732b 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -8,6 +8,7 @@ config DRM_ROCKCHIP select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP select DRM_DW_HDMI if ROCKCHIP_DW_HDMI select DRM_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI + select DRM_RGB if ROCKCHIP_RGB select SND_SOC_HDMI_CODEC if ROCKCHIP_CDN_DP && SND_SOC help Choose this option if you have a Rockchip soc chipset. @@ -23,7 +24,7 @@ config ROCKCHIP_ANALOGIX_DP help This selects support for Rockchip SoC specific extensions for the Analogix Core DP driver. If you want to enable DP - on RK3288 based SoC, you should selet this option. + on RK3288 or RK3399 based SoC, you should select this option. config ROCKCHIP_CDN_DP bool "Rockchip cdn DP" @@ -39,16 +40,16 @@ config ROCKCHIP_DW_HDMI help This selects support for Rockchip SoC specific extensions for the Synopsys DesignWare HDMI driver. If you want to - enable HDMI on RK3288 based SoC, you should selet this - option. + enable HDMI on RK3288 or RK3399 based SoC, you should select + this option. config ROCKCHIP_DW_MIPI_DSI bool "Rockchip specific extensions for Synopsys DW MIPI DSI" help - This selects support for Rockchip SoC specific extensions - for the Synopsys DesignWare HDMI driver. If you want to - enable MIPI DSI on RK3288 based SoC, you should selet this - option. + This selects support for Rockchip SoC specific extensions + for the Synopsys DesignWare HDMI driver. If you want to + enable MIPI DSI on RK3288 or RK3399 based SoC, you should + select this option. config ROCKCHIP_INNO_HDMI bool "Rockchip specific extensions for Innosilicon HDMI" @@ -66,4 +67,14 @@ config ROCKCHIP_LVDS Rockchip rk3288 SoC has LVDS TX Controller can be used, and it support LVDS, rgb, dual LVDS output mode. say Y to enable its driver. + +config ROCKCHIP_RGB + bool "Rockchip RGB support" + depends on DRM_ROCKCHIP + depends on PINCTRL + help + Choose this option to enable support for Rockchip RGB output. + Some Rockchip CRTCs, like rv1108, can directly output parallel + and serial RGB format to panel or connect to a conversion chip. + say Y to enable its driver. endif diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile index a314e2109e76..868263ff0302 100644 --- a/drivers/gpu/drm/rockchip/Makefile +++ b/drivers/gpu/drm/rockchip/Makefile @@ -14,5 +14,6 @@ rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o +rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index f814d37b1db2..941f35233b1f 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -24,6 +24,7 @@ #include <linux/pm_runtime.h> #include <linux/module.h> #include <linux/of_graph.h> +#include <linux/of_platform.h> #include <linux/component.h> #include <linux/console.h> #include <linux/iommu.h> @@ -184,7 +185,7 @@ err_mode_config_cleanup: err_free: drm_dev->dev_private = NULL; dev_set_drvdata(dev, NULL); - drm_dev_unref(drm_dev); + drm_dev_put(drm_dev); return ret; } @@ -204,7 +205,7 @@ static void rockchip_drm_unbind(struct device *dev) drm_dev->dev_private = NULL; dev_set_drvdata(dev, NULL); - drm_dev_unref(drm_dev); + drm_dev_put(drm_dev); } static const struct file_operations rockchip_drm_driver_fops = { @@ -243,60 +244,18 @@ static struct drm_driver rockchip_drm_driver = { }; #ifdef CONFIG_PM_SLEEP -static void rockchip_drm_fb_suspend(struct drm_device *drm) -{ - struct rockchip_drm_private *priv = drm->dev_private; - - console_lock(); - drm_fb_helper_set_suspend(&priv->fbdev_helper, 1); - console_unlock(); -} - -static void rockchip_drm_fb_resume(struct drm_device *drm) -{ - struct rockchip_drm_private *priv = drm->dev_private; - - console_lock(); - drm_fb_helper_set_suspend(&priv->fbdev_helper, 0); - console_unlock(); -} - static int rockchip_drm_sys_suspend(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); - struct rockchip_drm_private *priv; - - if (!drm) - return 0; - - drm_kms_helper_poll_disable(drm); - rockchip_drm_fb_suspend(drm); - priv = drm->dev_private; - priv->state = drm_atomic_helper_suspend(drm); - if (IS_ERR(priv->state)) { - rockchip_drm_fb_resume(drm); - drm_kms_helper_poll_enable(drm); - return PTR_ERR(priv->state); - } - - return 0; + return drm_mode_config_helper_suspend(drm); } static int rockchip_drm_sys_resume(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); - struct rockchip_drm_private *priv; - - if (!drm) - return 0; - priv = drm->dev_private; - drm_atomic_helper_resume(drm, priv->state); - rockchip_drm_fb_resume(drm); - drm_kms_helper_poll_enable(drm); - - return 0; + return drm_mode_config_helper_resume(drm); } #endif @@ -309,6 +268,53 @@ static const struct dev_pm_ops rockchip_drm_pm_ops = { static struct platform_driver *rockchip_sub_drivers[MAX_ROCKCHIP_SUB_DRIVERS]; static int num_rockchip_sub_drivers; +/* + * Check if a vop endpoint is leading to a rockchip subdriver or bridge. + * Should be called from the component bind stage of the drivers + * to ensure that all subdrivers are probed. + * + * @ep: endpoint of a rockchip vop + * + * returns true if subdriver, false if external bridge and -ENODEV + * if remote port does not contain a device. + */ +int rockchip_drm_endpoint_is_subdriver(struct device_node *ep) +{ + struct device_node *node = of_graph_get_remote_port_parent(ep); + struct platform_device *pdev; + struct device_driver *drv; + int i; + + if (!node) + return -ENODEV; + + /* status disabled will prevent creation of platform-devices */ + pdev = of_find_device_by_node(node); + of_node_put(node); + if (!pdev) + return -ENODEV; + + /* + * All rockchip subdrivers have probed at this point, so + * any device not having a driver now is an external bridge. + */ + drv = pdev->dev.driver; + if (!drv) { + platform_device_put(pdev); + return false; + } + + for (i = 0; i < num_rockchip_sub_drivers; i++) { + if (rockchip_sub_drivers[i] == to_platform_driver(drv)) { + platform_device_put(pdev); + return true; + } + } + + platform_device_put(pdev); + return false; +} + static int compare_dev(struct device *dev, void *data) { return dev == (struct device *)data; @@ -442,6 +448,11 @@ static int rockchip_drm_platform_remove(struct platform_device *pdev) return 0; } +static void rockchip_drm_platform_shutdown(struct platform_device *pdev) +{ + rockchip_drm_platform_remove(pdev); +} + static const struct of_device_id rockchip_drm_dt_ids[] = { { .compatible = "rockchip,display-subsystem", }, { /* sentinel */ }, @@ -451,6 +462,7 @@ MODULE_DEVICE_TABLE(of, rockchip_drm_dt_ids); static struct platform_driver rockchip_drm_platform_driver = { .probe = rockchip_drm_platform_probe, .remove = rockchip_drm_platform_remove, + .shutdown = rockchip_drm_platform_shutdown, .driver = { .name = "rockchip-drm", .of_match_table = rockchip_drm_dt_ids, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 3a6ebfc26036..21a023a97bb8 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -51,7 +51,6 @@ struct rockchip_crtc_state { struct rockchip_drm_private { struct drm_fb_helper fbdev_helper; struct drm_gem_object *fbdev_bo; - struct drm_atomic_state *state; struct iommu_domain *domain; struct mutex mm_lock; struct drm_mm mm; @@ -65,6 +64,7 @@ void rockchip_drm_dma_detach_device(struct drm_device *drm_dev, struct device *dev); int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout); +int rockchip_drm_endpoint_is_subdriver(struct device_node *ep); extern struct platform_driver cdn_dp_driver; extern struct platform_driver dw_hdmi_rockchip_pltfm_driver; extern struct platform_driver dw_mipi_dsi_driver; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 1359e5c773e4..0c35a88e33dd 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -32,6 +32,7 @@ #include <linux/of_device.h> #include <linux/pm_runtime.h> #include <linux/component.h> +#include <linux/overflow.h> #include <linux/reset.h> #include <linux/delay.h> @@ -41,6 +42,7 @@ #include "rockchip_drm_fb.h" #include "rockchip_drm_psr.h" #include "rockchip_drm_vop.h" +#include "rockchip_rgb.h" #define VOP_WIN_SET(x, win, name, v) \ vop_reg_set(vop, &win->phy->name, win->base, ~0, v, #name) @@ -92,6 +94,7 @@ struct vop_win { struct vop *vop; }; +struct rockchip_rgb; struct vop { struct drm_crtc crtc; struct device *dev; @@ -135,6 +138,9 @@ struct vop { /* vop dclk reset */ struct reset_control *dclk_rst; + /* optional internal rgb encoder */ + struct rockchip_rgb *rgb; + struct vop_win win[]; }; @@ -1111,7 +1117,7 @@ static struct drm_connector *vop_get_edp_connector(struct vop *vop) } static int vop_crtc_set_crc_source(struct drm_crtc *crtc, - const char *source_name, size_t *values_cnt) + const char *source_name) { struct vop *vop = to_vop(crtc); struct drm_connector *connector; @@ -1121,8 +1127,6 @@ static int vop_crtc_set_crc_source(struct drm_crtc *crtc, if (!connector) return -EINVAL; - *values_cnt = 3; - if (source_name && strcmp(source_name, "auto") == 0) ret = analogix_dp_start_crc(connector); else if (!source_name) @@ -1132,9 +1136,28 @@ static int vop_crtc_set_crc_source(struct drm_crtc *crtc, return ret; } + +static int +vop_crtc_verify_crc_source(struct drm_crtc *crtc, const char *source_name, + size_t *values_cnt) +{ + if (source_name && strcmp(source_name, "auto") != 0) + return -EINVAL; + + *values_cnt = 3; + return 0; +} + #else static int vop_crtc_set_crc_source(struct drm_crtc *crtc, - const char *source_name, size_t *values_cnt) + const char *source_name) +{ + return -ENODEV; +} + +static int +vop_crtc_verify_crc_source(struct drm_crtc *crtc, const char *source_name, + size_t *values_cnt) { return -ENODEV; } @@ -1150,6 +1173,7 @@ static const struct drm_crtc_funcs vop_crtc_funcs = { .enable_vblank = vop_crtc_enable_vblank, .disable_vblank = vop_crtc_disable_vblank, .set_crc_source = vop_crtc_set_crc_source, + .verify_crc_source = vop_crtc_verify_crc_source, }; static void vop_fb_unref_worker(struct drm_flip_work *work, void *val) @@ -1561,7 +1585,6 @@ static int vop_bind(struct device *dev, struct device *master, void *data) struct drm_device *drm_dev = data; struct vop *vop; struct resource *res; - size_t alloc_size; int ret, irq; vop_data = of_device_get_match_data(dev); @@ -1569,8 +1592,8 @@ static int vop_bind(struct device *dev, struct device *master, void *data) return -ENODEV; /* Allocate vop struct and its vop_win array */ - alloc_size = sizeof(*vop) + sizeof(*vop->win) * vop_data->win_size; - vop = devm_kzalloc(dev, alloc_size, GFP_KERNEL); + vop = devm_kzalloc(dev, struct_size(vop, win, vop_data->win_size), + GFP_KERNEL); if (!vop) return -ENOMEM; @@ -1620,6 +1643,14 @@ static int vop_bind(struct device *dev, struct device *master, void *data) if (ret) goto err_disable_pm_runtime; + if (vop->data->feature & VOP_FEATURE_INTERNAL_RGB) { + vop->rgb = rockchip_rgb_init(dev, &vop->crtc, vop->drm_dev); + if (IS_ERR(vop->rgb)) { + ret = PTR_ERR(vop->rgb); + goto err_disable_pm_runtime; + } + } + return 0; err_disable_pm_runtime: @@ -1632,6 +1663,9 @@ static void vop_unbind(struct device *dev, struct device *master, void *data) { struct vop *vop = dev_get_drvdata(dev); + if (vop->rgb) + rockchip_rgb_fini(vop->rgb); + pm_runtime_disable(dev); vop_destroy_crtc(vop); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index fcb91041a666..fd5765dfd637 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -162,6 +162,7 @@ struct vop_data { unsigned int win_size; #define VOP_FEATURE_OUTPUT_RGB10 BIT(0) +#define VOP_FEATURE_INTERNAL_RGB BIT(1) u64 feature; }; diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c new file mode 100644 index 000000000000..96ac1458a59c --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c @@ -0,0 +1,173 @@ +//SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: + * Sandy Huang <hjc@rock-chips.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <drm/drmP.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_dp_helper.h> +#include <drm/drm_panel.h> +#include <drm/drm_of.h> + +#include <linux/component.h> +#include <linux/of_graph.h> + +#include "rockchip_drm_drv.h" +#include "rockchip_drm_vop.h" + +#define encoder_to_rgb(c) container_of(c, struct rockchip_rgb, encoder) + +struct rockchip_rgb { + struct device *dev; + struct drm_device *drm_dev; + struct drm_bridge *bridge; + struct drm_encoder encoder; + int output_mode; +}; + +static int +rockchip_rgb_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); + struct drm_connector *connector = conn_state->connector; + struct drm_display_info *info = &connector->display_info; + u32 bus_format; + + if (info->num_bus_formats) + bus_format = info->bus_formats[0]; + else + bus_format = MEDIA_BUS_FMT_RGB888_1X24; + + switch (bus_format) { + case MEDIA_BUS_FMT_RGB666_1X18: + s->output_mode = ROCKCHIP_OUT_MODE_P666; + break; + case MEDIA_BUS_FMT_RGB565_1X16: + s->output_mode = ROCKCHIP_OUT_MODE_P565; + break; + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: + default: + s->output_mode = ROCKCHIP_OUT_MODE_P888; + break; + } + + s->output_type = DRM_MODE_CONNECTOR_LVDS; + + return 0; +} + +static const +struct drm_encoder_helper_funcs rockchip_rgb_encoder_helper_funcs = { + .atomic_check = rockchip_rgb_encoder_atomic_check, +}; + +static const struct drm_encoder_funcs rockchip_rgb_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +struct rockchip_rgb *rockchip_rgb_init(struct device *dev, + struct drm_crtc *crtc, + struct drm_device *drm_dev) +{ + struct rockchip_rgb *rgb; + struct drm_encoder *encoder; + struct device_node *port, *endpoint; + u32 endpoint_id; + int ret = 0, child_count = 0; + struct drm_panel *panel; + struct drm_bridge *bridge; + + rgb = devm_kzalloc(dev, sizeof(*rgb), GFP_KERNEL); + if (!rgb) + return ERR_PTR(-ENOMEM); + + rgb->dev = dev; + rgb->drm_dev = drm_dev; + + port = of_graph_get_port_by_id(dev->of_node, 0); + if (!port) + return ERR_PTR(-EINVAL); + + for_each_child_of_node(port, endpoint) { + if (of_property_read_u32(endpoint, "reg", &endpoint_id)) + endpoint_id = 0; + + if (rockchip_drm_endpoint_is_subdriver(endpoint) > 0) + continue; + + child_count++; + ret = drm_of_find_panel_or_bridge(dev->of_node, 0, endpoint_id, + &panel, &bridge); + if (!ret) + break; + } + + of_node_put(port); + + /* if the rgb output is not connected to anything, just return */ + if (!child_count) + return NULL; + + if (ret < 0) { + if (ret != -EPROBE_DEFER) + DRM_DEV_ERROR(dev, "failed to find panel or bridge %d\n", ret); + return ERR_PTR(ret); + } + + encoder = &rgb->encoder; + encoder->possible_crtcs = drm_crtc_mask(crtc); + + ret = drm_encoder_init(drm_dev, encoder, &rockchip_rgb_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret < 0) { + DRM_DEV_ERROR(drm_dev->dev, + "failed to initialize encoder: %d\n", ret); + return ERR_PTR(ret); + } + + drm_encoder_helper_add(encoder, &rockchip_rgb_encoder_helper_funcs); + + if (panel) { + bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_LVDS); + if (IS_ERR(bridge)) + return ERR_CAST(bridge); + } + + rgb->bridge = bridge; + + ret = drm_bridge_attach(encoder, rgb->bridge, NULL); + if (ret) { + DRM_DEV_ERROR(drm_dev->dev, + "failed to attach bridge: %d\n", ret); + goto err_free_encoder; + } + + return rgb; + +err_free_encoder: + drm_encoder_cleanup(encoder); + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(rockchip_rgb_init); + +void rockchip_rgb_fini(struct rockchip_rgb *rgb) +{ + drm_panel_bridge_remove(rgb->bridge); + drm_encoder_cleanup(&rgb->encoder); +} +EXPORT_SYMBOL_GPL(rockchip_rgb_fini); diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.h b/drivers/gpu/drm/rockchip/rockchip_rgb.h new file mode 100644 index 000000000000..38b52e63b2b0 --- /dev/null +++ b/drivers/gpu/drm/rockchip/rockchip_rgb.h @@ -0,0 +1,33 @@ +//SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: + * Sandy Huang <hjc@rock-chips.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifdef CONFIG_ROCKCHIP_RGB +struct rockchip_rgb *rockchip_rgb_init(struct device *dev, + struct drm_crtc *crtc, + struct drm_device *drm_dev); +void rockchip_rgb_fini(struct rockchip_rgb *rgb); +#else +static inline struct rockchip_rgb *rockchip_rgb_init(struct device *dev, + struct drm_crtc *crtc, + struct drm_device *drm_dev) +{ + return NULL; +} + +static inline void rockchip_rgb_fini(struct rockchip_rgb *rgb) +{ +} +#endif diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 08023d3ecb76..a6db3cd5544b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -177,6 +177,215 @@ static const struct vop_data rk3126_vop = { .win_size = ARRAY_SIZE(rk3126_vop_win_data), }; +static const int px30_vop_intrs[] = { + FS_INTR, + 0, 0, + LINE_FLAG_INTR, + 0, + BUS_ERROR_INTR, + 0, 0, + DSP_HOLD_VALID_INTR, +}; + +static const struct vop_intr px30_intr = { + .intrs = px30_vop_intrs, + .nintrs = ARRAY_SIZE(px30_vop_intrs), + .line_flag_num[0] = VOP_REG(PX30_LINE_FLAG, 0xfff, 0), + .status = VOP_REG_MASK_SYNC(PX30_INTR_STATUS, 0xffff, 0), + .enable = VOP_REG_MASK_SYNC(PX30_INTR_EN, 0xffff, 0), + .clear = VOP_REG_MASK_SYNC(PX30_INTR_CLEAR, 0xffff, 0), +}; + +static const struct vop_common px30_common = { + .standby = VOP_REG_SYNC(PX30_SYS_CTRL2, 0x1, 1), + .out_mode = VOP_REG(PX30_DSP_CTRL2, 0xf, 16), + .dsp_blank = VOP_REG(PX30_DSP_CTRL2, 0x1, 14), + .cfg_done = VOP_REG_SYNC(PX30_REG_CFG_DONE, 0x1, 0), +}; + +static const struct vop_modeset px30_modeset = { + .htotal_pw = VOP_REG(PX30_DSP_HTOTAL_HS_END, 0x0fff0fff, 0), + .hact_st_end = VOP_REG(PX30_DSP_HACT_ST_END, 0x0fff0fff, 0), + .vtotal_pw = VOP_REG(PX30_DSP_VTOTAL_VS_END, 0x0fff0fff, 0), + .vact_st_end = VOP_REG(PX30_DSP_VACT_ST_END, 0x0fff0fff, 0), +}; + +static const struct vop_output px30_output = { + .rgb_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0xf, 1), + .mipi_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0xf, 25), + .rgb_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 0), + .mipi_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 24), +}; + +static const struct vop_scl_regs px30_win_scl = { + .scale_yrgb_x = VOP_REG(PX30_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), + .scale_yrgb_y = VOP_REG(PX30_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), + .scale_cbcr_x = VOP_REG(PX30_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), + .scale_cbcr_y = VOP_REG(PX30_WIN0_SCL_FACTOR_CBR, 0xffff, 16), +}; + +static const struct vop_win_phy px30_win0_data = { + .scl = &px30_win_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .enable = VOP_REG(PX30_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(PX30_WIN0_CTRL0, 0x7, 1), + .rb_swap = VOP_REG(PX30_WIN0_CTRL0, 0x1, 12), + .act_info = VOP_REG(PX30_WIN0_ACT_INFO, 0xffffffff, 0), + .dsp_info = VOP_REG(PX30_WIN0_DSP_INFO, 0xffffffff, 0), + .dsp_st = VOP_REG(PX30_WIN0_DSP_ST, 0xffffffff, 0), + .yrgb_mst = VOP_REG(PX30_WIN0_YRGB_MST0, 0xffffffff, 0), + .uv_mst = VOP_REG(PX30_WIN0_CBR_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(PX30_WIN0_VIR, 0x1fff, 0), + .uv_vir = VOP_REG(PX30_WIN0_VIR, 0x1fff, 16), +}; + +static const struct vop_win_phy px30_win1_data = { + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + .enable = VOP_REG(PX30_WIN1_CTRL0, 0x1, 0), + .format = VOP_REG(PX30_WIN1_CTRL0, 0x7, 4), + .rb_swap = VOP_REG(PX30_WIN1_CTRL0, 0x1, 12), + .dsp_info = VOP_REG(PX30_WIN1_DSP_INFO, 0xffffffff, 0), + .dsp_st = VOP_REG(PX30_WIN1_DSP_ST, 0xffffffff, 0), + .yrgb_mst = VOP_REG(PX30_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(PX30_WIN1_VIR, 0x1fff, 0), +}; + +static const struct vop_win_phy px30_win2_data = { + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + .gate = VOP_REG(PX30_WIN2_CTRL0, 0x1, 4), + .enable = VOP_REG(PX30_WIN2_CTRL0, 0x1, 0), + .format = VOP_REG(PX30_WIN2_CTRL0, 0x3, 5), + .rb_swap = VOP_REG(PX30_WIN2_CTRL0, 0x1, 20), + .dsp_info = VOP_REG(PX30_WIN2_DSP_INFO0, 0x0fff0fff, 0), + .dsp_st = VOP_REG(PX30_WIN2_DSP_ST0, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(PX30_WIN2_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(PX30_WIN2_VIR0_1, 0x1fff, 0), +}; + +static const struct vop_win_data px30_vop_big_win_data[] = { + { .base = 0x00, .phy = &px30_win0_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x00, .phy = &px30_win1_data, + .type = DRM_PLANE_TYPE_OVERLAY }, + { .base = 0x00, .phy = &px30_win2_data, + .type = DRM_PLANE_TYPE_CURSOR }, +}; + +static const struct vop_data px30_vop_big = { + .intr = &px30_intr, + .feature = VOP_FEATURE_INTERNAL_RGB, + .common = &px30_common, + .modeset = &px30_modeset, + .output = &px30_output, + .win = px30_vop_big_win_data, + .win_size = ARRAY_SIZE(px30_vop_big_win_data), +}; + +static const struct vop_win_data px30_vop_lit_win_data[] = { + { .base = 0x00, .phy = &px30_win1_data, + .type = DRM_PLANE_TYPE_PRIMARY }, +}; + +static const struct vop_data px30_vop_lit = { + .intr = &px30_intr, + .feature = VOP_FEATURE_INTERNAL_RGB, + .common = &px30_common, + .modeset = &px30_modeset, + .output = &px30_output, + .win = px30_vop_lit_win_data, + .win_size = ARRAY_SIZE(px30_vop_lit_win_data), +}; + +static const struct vop_scl_regs rk3188_win_scl = { + .scale_yrgb_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), + .scale_yrgb_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 16), + .scale_cbcr_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), + .scale_cbcr_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_CBR, 0xffff, 16), +}; + +static const struct vop_win_phy rk3188_win0_data = { + .scl = &rk3188_win_scl, + .data_formats = formats_win_full, + .nformats = ARRAY_SIZE(formats_win_full), + .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 0), + .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 3), + .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 15), + .act_info = VOP_REG(RK3188_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3188_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3188_WIN0_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3188_WIN0_YRGB_MST0, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3188_WIN0_CBR_MST0, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 0), +}; + +static const struct vop_win_phy rk3188_win1_data = { + .data_formats = formats_win_lite, + .nformats = ARRAY_SIZE(formats_win_lite), + .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 1), + .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 6), + .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 19), + /* no act_info on window1 */ + .dsp_info = VOP_REG(RK3188_WIN1_DSP_INFO, 0x07ff07ff, 0), + .dsp_st = VOP_REG(RK3188_WIN1_DSP_ST, 0x0fff0fff, 0), + .yrgb_mst = VOP_REG(RK3188_WIN1_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 16), +}; + +static const struct vop_modeset rk3188_modeset = { + .htotal_pw = VOP_REG(RK3188_DSP_HTOTAL_HS_END, 0x0fff0fff, 0), + .hact_st_end = VOP_REG(RK3188_DSP_HACT_ST_END, 0x0fff0fff, 0), + .vtotal_pw = VOP_REG(RK3188_DSP_VTOTAL_VS_END, 0x0fff0fff, 0), + .vact_st_end = VOP_REG(RK3188_DSP_VACT_ST_END, 0x0fff0fff, 0), +}; + +static const struct vop_output rk3188_output = { + .pin_pol = VOP_REG(RK3188_DSP_CTRL0, 0xf, 4), +}; + +static const struct vop_common rk3188_common = { + .gate_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 31), + .standby = VOP_REG(RK3188_SYS_CTRL, 0x1, 30), + .out_mode = VOP_REG(RK3188_DSP_CTRL0, 0xf, 0), + .cfg_done = VOP_REG(RK3188_REG_CFG_DONE, 0x1, 0), + .dsp_blank = VOP_REG(RK3188_DSP_CTRL1, 0x3, 24), +}; + +static const struct vop_win_data rk3188_vop_win_data[] = { + { .base = 0x00, .phy = &rk3188_win0_data, + .type = DRM_PLANE_TYPE_PRIMARY }, + { .base = 0x00, .phy = &rk3188_win1_data, + .type = DRM_PLANE_TYPE_CURSOR }, +}; + +static const int rk3188_vop_intrs[] = { + 0, + FS_INTR, + LINE_FLAG_INTR, + BUS_ERROR_INTR, +}; + +static const struct vop_intr rk3188_vop_intr = { + .intrs = rk3188_vop_intrs, + .nintrs = ARRAY_SIZE(rk3188_vop_intrs), + .line_flag_num[0] = VOP_REG(RK3188_INT_STATUS, 0xfff, 12), + .status = VOP_REG(RK3188_INT_STATUS, 0xf, 0), + .enable = VOP_REG(RK3188_INT_STATUS, 0xf, 4), + .clear = VOP_REG(RK3188_INT_STATUS, 0xf, 8), +}; + +static const struct vop_data rk3188_vop = { + .intr = &rk3188_vop_intr, + .common = &rk3188_common, + .modeset = &rk3188_modeset, + .output = &rk3188_output, + .win = rk3188_vop_win_data, + .win_size = ARRAY_SIZE(rk3188_vop_win_data), + .feature = VOP_FEATURE_INTERNAL_RGB, +}; + static const struct vop_scl_extension rk3288_win_full_scl_ext = { .cbcr_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 31), .cbcr_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 30), @@ -541,6 +750,12 @@ static const struct of_device_id vop_driver_dt_match[] = { .data = &rk3036_vop }, { .compatible = "rockchip,rk3126-vop", .data = &rk3126_vop }, + { .compatible = "rockchip,px30-vop-big", + .data = &px30_vop_big }, + { .compatible = "rockchip,px30-vop-lit", + .data = &px30_vop_lit }, + { .compatible = "rockchip,rk3188-vop", + .data = &rk3188_vop }, { .compatible = "rockchip,rk3288-vop", .data = &rk3288_vop }, { .compatible = "rockchip,rk3368-vop", diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h index f81b510ea99c..7348c68352ed 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h @@ -884,4 +884,103 @@ #define RK3126_WIN1_DSP_ST 0x54 /* rk3126 register definition end */ +/* px30 register definition */ +#define PX30_REG_CFG_DONE 0x00000 +#define PX30_VERSION 0x00004 +#define PX30_DSP_BG 0x00008 +#define PX30_MCU_CTRL 0x0000c +#define PX30_SYS_CTRL0 0x00010 +#define PX30_SYS_CTRL1 0x00014 +#define PX30_SYS_CTRL2 0x00018 +#define PX30_DSP_CTRL0 0x00020 +#define PX30_DSP_CTRL2 0x00028 +#define PX30_VOP_STATUS 0x0002c +#define PX30_LINE_FLAG 0x00030 +#define PX30_INTR_EN 0x00034 +#define PX30_INTR_CLEAR 0x00038 +#define PX30_INTR_STATUS 0x0003c +#define PX30_WIN0_CTRL0 0x00050 +#define PX30_WIN0_CTRL1 0x00054 +#define PX30_WIN0_COLOR_KEY 0x00058 +#define PX30_WIN0_VIR 0x0005c +#define PX30_WIN0_YRGB_MST0 0x00060 +#define PX30_WIN0_CBR_MST0 0x00064 +#define PX30_WIN0_ACT_INFO 0x00068 +#define PX30_WIN0_DSP_INFO 0x0006c +#define PX30_WIN0_DSP_ST 0x00070 +#define PX30_WIN0_SCL_FACTOR_YRGB 0x00074 +#define PX30_WIN0_SCL_FACTOR_CBR 0x00078 +#define PX30_WIN0_SCL_OFFSET 0x0007c +#define PX30_WIN0_ALPHA_CTRL 0x00080 +#define PX30_WIN1_CTRL0 0x00090 +#define PX30_WIN1_CTRL1 0x00094 +#define PX30_WIN1_VIR 0x00098 +#define PX30_WIN1_MST 0x000a0 +#define PX30_WIN1_DSP_INFO 0x000a4 +#define PX30_WIN1_DSP_ST 0x000a8 +#define PX30_WIN1_COLOR_KEY 0x000ac +#define PX30_WIN1_ALPHA_CTRL 0x000bc +#define PX30_HWC_CTRL0 0x000e0 +#define PX30_HWC_CTRL1 0x000e4 +#define PX30_HWC_MST 0x000e8 +#define PX30_HWC_DSP_ST 0x000ec +#define PX30_HWC_ALPHA_CTRL 0x000f0 +#define PX30_DSP_HTOTAL_HS_END 0x00100 +#define PX30_DSP_HACT_ST_END 0x00104 +#define PX30_DSP_VTOTAL_VS_END 0x00108 +#define PX30_DSP_VACT_ST_END 0x0010c +#define PX30_DSP_VS_ST_END_F1 0x00110 +#define PX30_DSP_VACT_ST_END_F1 0x00114 +#define PX30_BCSH_CTRL 0x00160 +#define PX30_BCSH_COL_BAR 0x00164 +#define PX30_BCSH_BCS 0x00168 +#define PX30_BCSH_H 0x0016c +#define PX30_FRC_LOWER01_0 0x00170 +#define PX30_FRC_LOWER01_1 0x00174 +#define PX30_FRC_LOWER10_0 0x00178 +#define PX30_FRC_LOWER10_1 0x0017c +#define PX30_FRC_LOWER11_0 0x00180 +#define PX30_FRC_LOWER11_1 0x00184 +#define PX30_MCU_RW_BYPASS_PORT 0x0018c +#define PX30_WIN2_CTRL0 0x00190 +#define PX30_WIN2_CTRL1 0x00194 +#define PX30_WIN2_VIR0_1 0x00198 +#define PX30_WIN2_VIR2_3 0x0019c +#define PX30_WIN2_MST0 0x001a0 +#define PX30_WIN2_DSP_INFO0 0x001a4 +#define PX30_WIN2_DSP_ST0 0x001a8 +#define PX30_WIN2_COLOR_KEY 0x001ac +#define PX30_WIN2_ALPHA_CTRL 0x001bc +#define PX30_BLANKING_VALUE 0x001f4 +#define PX30_FLAG_REG_FRM_VALID 0x001f8 +#define PX30_FLAG_REG 0x001fc +#define PX30_HWC_LUT_ADDR 0x00600 +#define PX30_GAMMA_LUT_ADDR 0x00a00 +/* px30 register definition end */ + +/* rk3188 register definition */ +#define RK3188_SYS_CTRL 0x00 +#define RK3188_DSP_CTRL0 0x04 +#define RK3188_DSP_CTRL1 0x08 +#define RK3188_INT_STATUS 0x10 +#define RK3188_WIN0_YRGB_MST0 0x20 +#define RK3188_WIN0_CBR_MST0 0x24 +#define RK3188_WIN0_YRGB_MST1 0x28 +#define RK3188_WIN0_CBR_MST1 0x2c +#define RK3188_WIN_VIR 0x30 +#define RK3188_WIN0_ACT_INFO 0x34 +#define RK3188_WIN0_DSP_INFO 0x38 +#define RK3188_WIN0_DSP_ST 0x3c +#define RK3188_WIN0_SCL_FACTOR_YRGB 0x40 +#define RK3188_WIN0_SCL_FACTOR_CBR 0x44 +#define RK3188_WIN1_MST 0x4c +#define RK3188_WIN1_DSP_INFO 0x50 +#define RK3188_WIN1_DSP_ST 0x54 +#define RK3188_DSP_HTOTAL_HS_END 0x6c +#define RK3188_DSP_HACT_ST_END 0x70 +#define RK3188_DSP_VTOTAL_VS_END 0x74 +#define RK3188_DSP_VACT_ST_END 0x78 +#define RK3188_REG_CFG_DONE 0x90 +/* rk3188 register definition end */ + #endif /* _ROCKCHIP_VOP_REG_H */ |