diff --git a/drivers/video/drm/Kconfig b/drivers/video/drm/Kconfig index 305df5c5a5..04174ddece 100644 --- a/drivers/video/drm/Kconfig +++ b/drivers/video/drm/Kconfig @@ -10,10 +10,8 @@ menuconfig DRM_ROCKCHIP Rockchip RK3288 and RK3399. config DRM_ROCKCHIP_PANEL - bool - -config DRM_ROCKCHIP_DSI_PANEL - bool + bool "Rockchip Panel Support" + select DRM_ROCKCHIP_MIPI_DSI config DRM_ROCKCHIP_DW_HDMI bool "Rockchip specific extensions for Synopsys DW HDMI" @@ -30,7 +28,7 @@ config DRM_ROCKCHIP_DW_MIPI_DSI tristate "Rockchip specific extensions for Synopsys DW MIPI DSI" depends on DRM_ROCKCHIP select DRM_ROCKCHIP_MIPI_DSI - select DRM_ROCKCHIP_DSI_PANEL + select DRM_ROCKCHIP_PANEL help This selects support for Rockchip SoC specific extensions for the Synopsys DesignWare HDMI driver. If you want to diff --git a/drivers/video/drm/Makefile b/drivers/video/drm/Makefile index 9e865118fc..a9a85cb1a9 100644 --- a/drivers/video/drm/Makefile +++ b/drivers/video/drm/Makefile @@ -5,14 +5,12 @@ # obj-y += rockchip_display.o rockchip_crtc.o rockchip_phy.o \ - rockchip_vop.o rockchip_vop_reg.o bmp_helper.o \ - rockchip_panel.o + rockchip_vop.o rockchip_vop_reg.o bmp_helper.o obj-$(CONFIG_DRM_ROCKCHIP_MIPI_DSI) += rockchip_mipi_dsi.o obj-$(CONFIG_DRM_ROCKCHIP_DW_MIPI_DSI) += rockchip-dw-mipi-dsi.o \ - rockchip-inno-mipi-dphy.o rockchip_dsi_panel.o + rockchip-inno-mipi-dphy.o obj-$(CONFIG_DRM_ROCKCHIP_DW_HDMI) += rockchip_dw_hdmi.o dw_hdmi.o obj-$(CONFIG_DRM_ROCKCHIP_ANALOGIX_DP) += rockchip_analogix_dp.o rockchip_analogix_dp_reg.o obj-$(CONFIG_DRM_ROCKCHIP_LVDS) += rockchip_lvds.o -obj-$(CONFIG_DRM_ROCKCHIP_PANEL) += panel_simple.o -obj-$(CONFIG_DRM_ROCKCHIP_DSI_PANEL) += rockchip_dsi_panel.o +obj-$(CONFIG_DRM_ROCKCHIP_PANEL) += rockchip_panel.o diff --git a/drivers/video/drm/panel_simple.c b/drivers/video/drm/panel_simple.c deleted file mode 100644 index d577d33ebd..0000000000 --- a/drivers/video/drm/panel_simple.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rockchip_display.h" -#include "rockchip_crtc.h" -#include "rockchip_connector.h" -#include "rockchip_panel.h" - -#define msleep(a) udelay(a * 1000) - -struct panel_simple { - struct udevice *dev; - const void *blob; - ofnode node; - - const struct drm_display_mode *mode; - int bus_format; - - struct udevice *power_supply; - bool power_invert; - struct udevice *backlight; - struct gpio_desc enable; - - int delay_prepare; - int delay_unprepare; - int delay_enable; - int delay_disable; -}; - -static int panel_simple_prepare(struct display_state *state) -{ - struct panel_state *panel_state = &state->panel_state; - struct panel_simple *panel = panel_state->private; - int ret; - - if (panel->power_supply) { - ret = regulator_set_enable(panel->power_supply, - panel->power_invert); - if (ret) - printf("%s: failed to enable power_supply", - __func__); - } - - dm_gpio_set_value(&panel->enable, 1); - mdelay(panel->delay_prepare); - - return 0; -} - -static int panel_simple_unprepare(struct display_state *state) -{ - struct panel_state *panel_state = &state->panel_state; - struct panel_simple *panel = panel_state->private; - - dm_gpio_set_value(&panel->enable, 0); - mdelay(panel->delay_unprepare); - - return 0; -} - -static int panel_simple_enable(struct display_state *state) -{ - struct panel_state *panel_state = &state->panel_state; - struct panel_simple *panel = panel_state->private; - int ret; - - if (panel->backlight) { - ret = backlight_enable(panel->backlight); - mdelay(panel->delay_enable); - return ret; - } - - return 0; -} - -static int panel_simple_disable(struct display_state *state) -{ - struct panel_state *panel_state = &state->panel_state; - struct panel_simple *panel = panel_state->private; - int ret; - - if (panel->backlight) { - ret = backlight_disable(panel->backlight); - mdelay(panel->delay_disable); - return ret; - } - - return 0; -} - -static int panel_simple_parse_dt(const void *blob, ofnode node, - struct panel_simple *panel) -{ - int ret; - - ret = gpio_request_by_name(panel->dev, "enable-gpios", 0, - &panel->enable, GPIOD_IS_OUT); - if (ret && ret != -ENOENT) { - printf("%s: Warning: cannot get enable GPIO: ret=%d\n", - __func__, ret); - return ret; - } - - ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, panel->dev, - "backlight", &panel->backlight); - if (ret && ret != -ENOENT) { - printf("%s: Cannot get backlight: ret=%d\n", __func__, ret); - return ret; - } - - ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, panel->dev, - "power-supply", - &panel->power_supply); - if (ret && ret != -ENOENT) { - printf("%s: Cannot get power supply: ret=%d\n", __func__, ret); - return ret; - } - - panel->power_invert = !!ofnode_read_s32_default(node, "power_invert", 0); - - panel->delay_prepare = ofnode_read_s32_default(node, "prepare-delay-ms", 0); - panel->delay_unprepare = ofnode_read_s32_default(node, "unprepare-delay-ms", 0); - panel->delay_enable = ofnode_read_s32_default(node, "enable-delay-ms", 0); - panel->delay_disable = ofnode_read_s32_default(node, "disable-delay-ms", 0); - panel->bus_format = ofnode_read_s32_default(node, "bus-format", MEDIA_BUS_FMT_RBG888_1X24); - - debug("delay prepare[%d] unprepare[%d] enable[%d] disable[%d]\n", - panel->delay_prepare, panel->delay_unprepare, - panel->delay_enable, panel->delay_disable); - - /* keep panel blank on init. */ - dm_gpio_set_value(&panel->enable, 0); - - return 0; -} - -static int panel_simple_init(struct display_state *state) -{ - const void *blob = state->blob; - struct connector_state *conn_state = &state->conn_state; - struct panel_state *panel_state = &state->panel_state; - ofnode node = panel_state->node; - const struct drm_display_mode *mode = panel_state->panel->data; - struct panel_simple *panel; - int ret; - - panel = malloc(sizeof(*panel)); - if (!panel) - return -ENOMEM; - - memset(panel, 0, sizeof(*panel)); - panel->blob = blob; - panel->node = node; - panel->mode = mode; - panel->dev = panel_state->dev; - panel_state->private = panel; - - ret = panel_simple_parse_dt(blob, node, panel); - if (ret) { - printf("%s: failed to parse DT\n", __func__); - free(panel); - return ret; - } - - conn_state->bus_format = panel->bus_format; - - return 0; -} - -static void panel_simple_deinit(struct display_state *state) -{ - struct panel_state *panel_state = &state->panel_state; - struct panel_simple *panel = panel_state->private; - - free(panel); -} - -const struct rockchip_panel_funcs panel_simple_funcs = { - .init = panel_simple_init, - .deinit = panel_simple_deinit, - .prepare = panel_simple_prepare, - .unprepare = panel_simple_unprepare, - .enable = panel_simple_enable, - .disable = panel_simple_disable, -}; diff --git a/drivers/video/drm/rockchip_display.c b/drivers/video/drm/rockchip_display.c index 77df5c2b53..6980c137e3 100644 --- a/drivers/video/drm/rockchip_display.c +++ b/drivers/video/drm/rockchip_display.c @@ -199,10 +199,12 @@ static int connector_panel_init(struct display_state *state) panel_state->dev = dev; panel_state->panel = panel; - ret = rockchip_panel_init(state); - if (ret) { - printf("failed to init panel driver\n"); - return ret; + if (panel->funcs && panel->funcs->init) { + ret = panel->funcs->init(state); + if (ret) { + printf("failed to init panel driver\n"); + return ret; + } } dsp_lut_node = dev_read_subnode(dev, "dsp-lut"); @@ -409,31 +411,44 @@ static int display_get_timing(struct display_state *state) struct drm_display_mode *mode = &conn_state->mode; const struct drm_display_mode *m; struct panel_state *panel_state = &state->panel_state; - ofnode panel = panel_state->node; + const struct rockchip_panel *panel = panel_state->panel; + const struct rockchip_panel_funcs *panel_funcs = panel->funcs; + ofnode panel_node = panel_state->node; + int ret; - if (ofnode_valid(panel) && !display_get_timing_from_dts(panel_state, mode)) { + if (ofnode_valid(panel_node) && !display_get_timing_from_dts(panel_state, mode)) { printf("Using display timing dts\n"); goto done; } - m = rockchip_get_display_mode_from_panel(state); - if (m) { - printf("Using display timing from compatible panel driver\n"); + if (panel->data) { + m = (const struct drm_display_mode *)panel->data; memcpy(mode, m, sizeof(*m)); + printf("Using display timing from compatible panel driver\n"); goto done; } - rockchip_panel_prepare(state); - if (conn_funcs->get_edid && !conn_funcs->get_edid(state)) { int panel_bits_per_colourp; + /* In order to read EDID, the panel needs to be powered on */ + if (panel_funcs->prepare) { + ret = panel_funcs->prepare(state); + if (ret) { + printf("failed to prepare panel\n"); + return ret; + } + } + if (!edid_get_drm_mode((void *)&conn_state->edid, sizeof(conn_state->edid), mode, &panel_bits_per_colourp)) { printf("Using display timing from edid\n"); edid_print_info((void *)&conn_state->edid); goto done; + } else { + if (panel_funcs->unprepare) + panel_funcs->unprepare(state); } } @@ -547,6 +562,9 @@ static int display_enable(struct display_state *state) struct crtc_state *crtc_state = &state->crtc_state; const struct rockchip_crtc *crtc = crtc_state->crtc; const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs; + struct panel_state *panel_state = &state->panel_state; + const struct rockchip_panel *panel = panel_state->panel; + const struct rockchip_panel_funcs *panel_funcs = panel->funcs; int ret = 0; display_init(state); @@ -569,12 +587,18 @@ static int display_enable(struct display_state *state) goto unprepare_crtc; } - rockchip_panel_prepare(state); + if (panel_funcs->prepare) { + ret = panel_funcs->prepare(state); + if (ret) { + printf("failed to prepare panel\n"); + goto unprepare_conn; + } + } if (crtc_funcs->enable) { ret = crtc_funcs->enable(state); if (ret) - goto unprepare_conn; + goto unprepare_panel; } if (conn_funcs->enable) { @@ -583,20 +607,33 @@ static int display_enable(struct display_state *state) goto disable_crtc; } - rockchip_panel_enable(state); + if (panel_funcs->enable) { + ret = panel_funcs->enable(state); + if (ret) { + printf("failed to enable panel\n"); + goto disable_conn; + } + } state->is_enable = true; return 0; -unprepare_crtc: - if (crtc_funcs->unprepare) - crtc_funcs->unprepare(state); -unprepare_conn: + +disable_conn: if (conn_funcs->unprepare) conn_funcs->unprepare(state); disable_crtc: if (crtc_funcs->disable) crtc_funcs->disable(state); +unprepare_crtc: + if (crtc_funcs->unprepare) + crtc_funcs->unprepare(state); +unprepare_panel: + if (panel_funcs->unprepare) + panel_funcs->unprepare(state); +unprepare_conn: + if (conn_funcs->unprepare) + conn_funcs->unprepare(state); return ret; } @@ -608,6 +645,9 @@ static int display_disable(struct display_state *state) struct crtc_state *crtc_state = &state->crtc_state; const struct rockchip_crtc *crtc = crtc_state->crtc; const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs; + struct panel_state *panel_state = &state->panel_state; + const struct rockchip_panel *panel = panel_state->panel; + const struct rockchip_panel_funcs *panel_funcs = panel->funcs; if (!state->is_init) return 0; @@ -615,7 +655,8 @@ static int display_disable(struct display_state *state) if (!state->is_enable) return 0; - rockchip_panel_disable(state); + if (panel_funcs->disable) + panel_funcs->disable(state); if (crtc_funcs->disable) crtc_funcs->disable(state); @@ -623,7 +664,8 @@ static int display_disable(struct display_state *state) if (conn_funcs->disable) conn_funcs->disable(state); - rockchip_panel_unprepare(state); + if (panel_funcs->unprepare) + panel_funcs->unprepare(state); if (conn_funcs->unprepare) conn_funcs->unprepare(state); diff --git a/drivers/video/drm/rockchip_dsi_panel.c b/drivers/video/drm/rockchip_dsi_panel.c deleted file mode 100755 index 95ffa3238e..0000000000 --- a/drivers/video/drm/rockchip_dsi_panel.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rockchip_display.h" -#include "rockchip_crtc.h" -#include "rockchip_connector.h" -#include "rockchip_panel.h" -#include "rockchip_mipi_dsi.h" - -#define msleep(a) udelay(a * 1000) - -struct dsi_ctrl_hdr { - u8 dtype; /* data type */ - u8 wait; /* ms */ - u8 dlen; /* payload len */ -} __packed; - -struct dsi_cmd_desc { - struct dsi_ctrl_hdr dchdr; - u8 *payload; -}; - -struct dsi_panel_cmds { - u8 *buf; - int blen; - struct dsi_cmd_desc *cmds; - int cmd_cnt; -}; - -struct rockchip_dsi_panel { - struct udevice *dev; - const void *blob; - ofnode node; - - int bus_format; - - struct udevice *power_supply; - bool power_invert; - struct udevice *backlight; - struct gpio_desc enable; - struct gpio_desc reset; - - unsigned int delay_reset; - unsigned int delay_prepare; - unsigned int delay_unprepare; - unsigned int delay_enable; - unsigned int delay_disable; - unsigned int delay_init; - - struct dsi_panel_cmds *on_cmds; - struct dsi_panel_cmds *off_cmds; -}; - -static int rockchip_dsi_panel_parse_cmds(ofnode node, - const u8 *data, int blen, - struct dsi_panel_cmds *pcmds) -{ - int len; - u8 *buf, *bp; - struct dsi_ctrl_hdr *dchdr; - int i, cnt; - - if (!pcmds) - return -EINVAL; - - buf = malloc(sizeof(char) * blen); - if (!buf) - return -ENOMEM; - - memcpy(buf, data, blen); - - /* scan dcs commands */ - bp = buf; - len = blen; - cnt = 0; - while (len > sizeof(*dchdr)) { - dchdr = (struct dsi_ctrl_hdr *)bp; - if (dchdr->dlen > len) { - printf("%s: dtsi cmd=%x error, len=%d", - __func__, dchdr->dtype, dchdr->dlen); - free(buf); - return -ENOMEM; - } - - bp += sizeof(*dchdr); - len -= sizeof(*dchdr); - bp += dchdr->dlen; - len -= dchdr->dlen; - cnt++; - } - - if (len != 0) { - printf("%s: dcs_cmd=%x len=%d error!", __func__, buf[0], blen); - free(buf); - return -ENOMEM; - } - - pcmds->cmds = malloc(cnt * sizeof(struct dsi_cmd_desc)); - if (!pcmds->cmds) { - free(buf); - return -ENOMEM; - } - - pcmds->cmd_cnt = cnt; - pcmds->buf = buf; - pcmds->blen = blen; - - bp = buf; - len = blen; - for (i = 0; i < cnt; i++) { - dchdr = (struct dsi_ctrl_hdr *)bp; - len -= sizeof(*dchdr); - bp += sizeof(*dchdr); - pcmds->cmds[i].dchdr = *dchdr; - pcmds->cmds[i].payload = bp; - bp += dchdr->dlen; - len -= dchdr->dlen; - } - - debug("%s: total_len=%d, cmd_cnt=%d\n", - __func__, pcmds->blen, pcmds->cmd_cnt); - return 0; -} - -static int rockchip_dsi_panel_send_cmds(struct display_state *state, - struct dsi_panel_cmds *cmds) -{ - int i, ret; - - if (!cmds) - return -EINVAL; - - for (i = 0; i < cmds->cmd_cnt; i++) { - switch (cmds->cmds[i].dchdr.dtype) { - case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: - case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: - case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: - case MIPI_DSI_GENERIC_LONG_WRITE: - ret = mipi_dsi_generic_write(state, cmds->cmds[i].payload, - cmds->cmds[i].dchdr.dlen); - break; - case MIPI_DSI_DCS_SHORT_WRITE: - case MIPI_DSI_DCS_SHORT_WRITE_PARAM: - case MIPI_DSI_DCS_LONG_WRITE: - ret = mipi_dsi_dcs_write(state, cmds->cmds[i].payload, - cmds->cmds[i].dchdr.dlen); - break; - default: - return -EINVAL; - } - - if (ret) - printf("failed to write cmd%d: %d\n", i, ret); - - if (cmds->cmds[i].dchdr.wait) - msleep(cmds->cmds[i].dchdr.wait); - } - - return 0; -} - -static int rockchip_dsi_panel_prepare(struct display_state *state) -{ - struct panel_state *panel_state = &state->panel_state; - struct rockchip_dsi_panel *panel = panel_state->private; - int ret; - - if (panel->power_supply) { - ret = regulator_set_enable(panel->power_supply, - panel->power_invert); - if (ret) - printf("%s: failed to enable power_supply", - __func__); - } - - dm_gpio_set_value(&panel->enable, 1); - msleep(panel->delay_prepare); - - dm_gpio_set_value(&panel->reset, 1); - msleep(panel->delay_reset); - dm_gpio_set_value(&panel->reset, 0); - - msleep(panel->delay_init); - - if (panel->on_cmds) { - ret = rockchip_dsi_panel_send_cmds(state, panel->on_cmds); - if (ret) - printf("failed to send on cmds: %d\n", ret); - } - - return 0; -} - -static int rockchip_dsi_panel_unprepare(struct display_state *state) -{ - struct panel_state *panel_state = &state->panel_state; - struct rockchip_dsi_panel *panel = panel_state->private; - int ret; - - if (panel->off_cmds) { - ret = rockchip_dsi_panel_send_cmds(state, panel->off_cmds); - if (ret) - printf("failed to send on cmds: %d\n", ret); - } - - dm_gpio_set_value(&panel->reset, 0); - - mdelay(panel->delay_unprepare); - - dm_gpio_set_value(&panel->enable, 0); - - return 0; -} - -static int rockchip_dsi_panel_enable(struct display_state *state) -{ - struct panel_state *panel_state = &state->panel_state; - struct rockchip_dsi_panel *panel = panel_state->private; - int ret; - - if (panel->backlight) { - ret = backlight_enable(panel->backlight); - mdelay(panel->delay_enable); - return ret; - } - - return 0; -} - -static int rockchip_dsi_panel_disable(struct display_state *state) -{ - struct panel_state *panel_state = &state->panel_state; - struct rockchip_dsi_panel *panel = panel_state->private; - int ret; - - if (panel->backlight) { - ret = backlight_disable(panel->backlight); - mdelay(panel->delay_disable); - return ret; - } - - return 0; -} - -static int rockchip_dsi_panel_parse_dt(ofnode node, struct rockchip_dsi_panel *panel) -{ - const void *data; - int len = 0; - int ret = 0; - - panel->delay_prepare = ofnode_read_u32_default(node, "prepare-delay-ms", 0); - panel->delay_unprepare = ofnode_read_u32_default(node, "unprepare-delay-ms", 0); - panel->delay_enable = ofnode_read_u32_default(node, "enable-delay-ms", 0); - panel->delay_disable = ofnode_read_u32_default(node, "disable-delay-ms", 0); - panel->delay_init = ofnode_read_u32_default(node, "init-delay-ms", 0); - panel->delay_reset = ofnode_read_u32_default(node, "reset-delay-ms", 0); - panel->bus_format = ofnode_read_u32_default(node, "bus-format", MEDIA_BUS_FMT_RBG888_1X24); - - data = ofnode_get_property(node, "panel-init-sequence", &len); - if (data) { - panel->on_cmds = malloc(sizeof(*panel->on_cmds)); - if (!panel->on_cmds) - return -ENOMEM; - - ret = rockchip_dsi_panel_parse_cmds(node, data, len, - panel->on_cmds); - if (ret) { - printf("failed to parse panel init sequence\n"); - goto free_on_cmds; - } - } - - data = ofnode_get_property(node, "panel-exit-sequence", &len); - if (data) { - panel->off_cmds = malloc(sizeof(*panel->off_cmds)); - if (!panel->off_cmds) { - ret = -ENOMEM; - goto free_on_cmds; - } - - ret = rockchip_dsi_panel_parse_cmds(node, data, len, - panel->off_cmds); - if (ret) { - printf("failed to parse panel exit sequence\n"); - goto free_cmds; - } - } - - ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, panel->dev, - "backlight", &panel->backlight); - if (ret) { - printf("%s: Cannot get backlight: ret=%d\n", __func__, ret); - return ret; - } - - ret = gpio_request_by_name(panel->dev, "enable-gpios", 0, - &panel->enable, GPIOD_IS_OUT); - if (ret && ret != -ENOENT) { - printf("%s: Warning: cannot get enable GPIO: ret=%d\n", - __func__, ret); - return ret; - } - - ret = gpio_request_by_name(panel->dev, "reset-gpios", 0, - &panel->reset, GPIOD_IS_OUT); - if (ret && ret != -ENOENT) { - printf("%s: Warning: cannot get reset GPIO: ret=%d\n", - __func__, ret); - return ret; - } - - ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, panel->dev, - "power-supply", - &panel->power_supply); - if (ret && ret != -ENOENT) { - printf("%s: Cannot get power supply: ret=%d\n", __func__, ret); - return ret; - } - - panel->power_invert = !!ofnode_read_u32_default(node, "power_invert", 0); - - /* keep panel blank on init. */ - dm_gpio_set_value(&panel->enable, 0); - dm_gpio_set_value(&panel->reset, 0); - - return 0; - -free_cmds: - free(panel->off_cmds); -free_on_cmds: - free(panel->on_cmds); - return ret; -} - -static int rockchip_dsi_panel_init(struct display_state *state) -{ - const void *blob = state->blob; - struct connector_state *conn_state = &state->conn_state; - struct panel_state *panel_state = &state->panel_state; - ofnode node = panel_state->node; - struct rockchip_dsi_panel *panel; - int ret; - - panel = malloc(sizeof(*panel)); - if (!panel) - return -ENOMEM; - - memset(panel, 0, sizeof(*panel)); - - panel->blob = blob; - panel->node = node; - panel->dev = panel_state->dev; - panel_state->private = panel; - - ret = rockchip_dsi_panel_parse_dt(node, panel); - if (ret) { - printf("%s: failed to parse DT\n", __func__); - free(panel); - return ret; - } - - conn_state->bus_format = panel->bus_format; - - return 0; -} - -static void rockchip_dsi_panel_deinit(struct display_state *state) -{ - struct panel_state *panel_state = &state->panel_state; - struct rockchip_dsi_panel *panel = panel_state->private; - - if (panel->on_cmds) { - free(panel->on_cmds->buf); - free(panel->on_cmds->cmds); - } - - if (panel->off_cmds) { - free(panel->off_cmds->buf); - free(panel->off_cmds->cmds); - } - - free(panel); -} - -const struct rockchip_panel_funcs rockchip_dsi_panel_funcs = { - .init = rockchip_dsi_panel_init, - .deinit = rockchip_dsi_panel_deinit, - .prepare = rockchip_dsi_panel_prepare, - .unprepare = rockchip_dsi_panel_unprepare, - .enable = rockchip_dsi_panel_enable, - .disable = rockchip_dsi_panel_disable, -}; diff --git a/drivers/video/drm/rockchip_panel.c b/drivers/video/drm/rockchip_panel.c index 5e0e85d7e1..69b056d062 100644 --- a/drivers/video/drm/rockchip_panel.c +++ b/drivers/video/drm/rockchip_panel.c @@ -4,18 +4,372 @@ * SPDX-License-Identifier: GPL-2.0+ */ -#include #include #include #include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include #include "rockchip_display.h" #include "rockchip_crtc.h" #include "rockchip_connector.h" +#include "rockchip_mipi_dsi.h" #include "rockchip_panel.h" -#ifdef CONFIG_DRM_ROCKCHIP_PANEL +struct rockchip_cmd_header { + u8 data_type; + u8 delay_ms; + u8 payload_length; +} __packed; + +struct rockchip_cmd_desc { + struct rockchip_cmd_header header; + const u8 *payload; +}; + +struct rockchip_panel_cmds { + struct rockchip_cmd_desc *cmds; + int cmd_cnt; +}; + +struct rockchip_panel_plat { + bool power_invert; + u32 bus_format; + + struct { + unsigned int prepare; + unsigned int unprepare; + unsigned int enable; + unsigned int disable; + unsigned int reset; + unsigned int init; + } delay; + + struct rockchip_panel_cmds *on_cmds; + struct rockchip_panel_cmds *off_cmds; +}; + +struct rockchip_panel_priv { + bool prepared; + bool enabled; + struct udevice *power_supply; + struct udevice *backlight; + struct gpio_desc enable_gpio; + struct gpio_desc reset_gpio; +}; + +static int rockchip_panel_parse_cmds(const u8 *data, int length, + struct rockchip_panel_cmds *pcmds) +{ + int len; + const u8 *buf; + const struct rockchip_cmd_header *header; + int i, cnt = 0; + + /* scan commands */ + cnt = 0; + buf = data; + len = length; + while (len > sizeof(*header)) { + header = (const struct rockchip_cmd_header *)buf; + buf += sizeof(*header) + header->payload_length; + len -= sizeof(*header) + header->payload_length; + cnt++; + } + + pcmds->cmds = calloc(cnt, sizeof(struct rockchip_cmd_desc)); + if (!pcmds->cmds) + return -ENOMEM; + + pcmds->cmd_cnt = cnt; + + buf = data; + len = length; + for (i = 0; i < cnt; i++) { + struct rockchip_cmd_desc *desc = &pcmds->cmds[i]; + + header = (const struct rockchip_cmd_header *)buf; + length -= sizeof(*header); + buf += sizeof(*header); + desc->header.data_type = header->data_type; + desc->header.delay_ms = header->delay_ms; + desc->header.payload_length = header->payload_length; + desc->payload = buf; + buf += header->payload_length; + length -= header->payload_length; + } + + return 0; +} + +static int rockchip_panel_send_cmds(struct display_state *state, + struct rockchip_panel_cmds *cmds) +{ + int i, ret; + + if (!cmds) + return -EINVAL; + + for (i = 0; i < cmds->cmd_cnt; i++) { + struct rockchip_cmd_desc *desc = &cmds->cmds[i]; + + switch (desc->header.data_type) { + case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: + case MIPI_DSI_GENERIC_LONG_WRITE: + ret = mipi_dsi_generic_write(state, desc->payload, + desc->header.payload_length); + break; + case MIPI_DSI_DCS_SHORT_WRITE: + case MIPI_DSI_DCS_SHORT_WRITE_PARAM: + case MIPI_DSI_DCS_LONG_WRITE: + ret = mipi_dsi_dcs_write(state, desc->payload, + desc->header.payload_length); + break; + default: + printf("unsupport command data type: %d\n", + desc->header.data_type); + return -EINVAL; + } + + if (ret) { + printf("failed to write cmd%d: %d\n", i, ret); + return ret; + } + + if (desc->header.delay_ms) + mdelay(desc->header.delay_ms); + } + + return 0; +} + +static int rockchip_panel_prepare(struct display_state *state) +{ + struct panel_state *panel_state = &state->panel_state; + struct rockchip_panel_plat *plat = dev_get_platdata(panel_state->dev); + struct rockchip_panel_priv *priv = dev_get_priv(panel_state->dev); + int ret; + + if (priv->prepared) + return 0; + + if (priv->power_supply) { + ret = regulator_set_enable(priv->power_supply, + !plat->power_invert); + if (ret) { + printf("%s: failed to enable power supply", __func__); + return ret; + } + } + + dm_gpio_set_value(&priv->enable_gpio, 1); + mdelay(plat->delay.prepare); + + dm_gpio_set_value(&priv->reset_gpio, 1); + mdelay(plat->delay.reset); + dm_gpio_set_value(&priv->reset_gpio, 0); + + mdelay(plat->delay.init); + + if (plat->on_cmds) { + ret = rockchip_panel_send_cmds(state, plat->on_cmds); + if (ret) + printf("failed to send on cmds: %d\n", ret); + } + + priv->prepared = true; + + return 0; +} + +static void rockchip_panel_unprepare(struct display_state *state) +{ + struct panel_state *panel_state = &state->panel_state; + struct rockchip_panel_plat *plat = dev_get_platdata(panel_state->dev); + struct rockchip_panel_priv *priv = dev_get_priv(panel_state->dev); + int ret; + + if (!priv->prepared) + return; + + if (plat->off_cmds) { + ret = rockchip_panel_send_cmds(state, plat->off_cmds); + if (ret) + printf("failed to send off cmds: %d\n", ret); + } + + dm_gpio_set_value(&priv->reset_gpio, 1); + dm_gpio_set_value(&priv->enable_gpio, 0); + + if (priv->power_supply) { + ret = regulator_set_enable(priv->power_supply, + plat->power_invert); + if (ret) + printf("%s: failed to disable power supply", __func__); + } + + mdelay(plat->delay.unprepare); + + priv->prepared = false; +} + +static int rockchip_panel_enable(struct display_state *state) +{ + struct panel_state *panel_state = &state->panel_state; + struct rockchip_panel_plat *plat = dev_get_platdata(panel_state->dev); + struct rockchip_panel_priv *priv = dev_get_priv(panel_state->dev); + + if (priv->enabled) + return 0; + + mdelay(plat->delay.enable); + + if (priv->backlight) + backlight_enable(priv->backlight); + + priv->enabled = true; + + return 0; +} + +static void rockchip_panel_disable(struct display_state *state) +{ + struct panel_state *panel_state = &state->panel_state; + struct rockchip_panel_plat *plat = dev_get_platdata(panel_state->dev); + struct rockchip_panel_priv *priv = dev_get_priv(panel_state->dev); + + if (!priv->enabled) + return; + + if (priv->backlight) + backlight_disable(priv->backlight); + + mdelay(plat->delay.disable); + + priv->enabled = false; +} + +static int rockchip_panel_init(struct display_state *state) +{ + struct connector_state *conn_state = &state->conn_state; + struct panel_state *panel_state = &state->panel_state; + struct rockchip_panel_plat *plat = dev_get_platdata(panel_state->dev); + + conn_state->bus_format = plat->bus_format; + + return 0; +} + +static const struct rockchip_panel_funcs rockchip_panel_funcs = { + .init = rockchip_panel_init, + .prepare = rockchip_panel_prepare, + .unprepare = rockchip_panel_unprepare, + .enable = rockchip_panel_enable, + .disable = rockchip_panel_disable, +}; + +static int rockchip_panel_ofdata_to_platdata(struct udevice *dev) +{ + struct rockchip_panel_plat *plat = dev_get_platdata(dev); + const void *data; + int len = 0; + int ret; + + plat->power_invert = dev_read_bool(dev, "power-invert"); + + plat->delay.prepare = dev_read_u32_default(dev, "prepare-delay-ms", 0); + plat->delay.unprepare = dev_read_u32_default(dev, "unprepare-delay-ms", 0); + plat->delay.enable = dev_read_u32_default(dev, "enable-delay-ms", 0); + plat->delay.disable = dev_read_u32_default(dev, "disable-delay-ms", 0); + plat->delay.init = dev_read_u32_default(dev, "init-delay-ms", 0); + plat->delay.reset = dev_read_u32_default(dev, "reset-delay-ms", 0); + + plat->bus_format = dev_read_u32_default(dev, "bus-format", + MEDIA_BUS_FMT_RBG888_1X24); + + data = dev_read_prop(dev, "panel-init-sequence", &len); + if (data) { + plat->on_cmds = calloc(1, sizeof(*plat->on_cmds)); + if (!plat->on_cmds) + return -ENOMEM; + + ret = rockchip_panel_parse_cmds(data, len, plat->on_cmds); + if (ret) { + printf("failed to parse panel init sequence\n"); + goto free_on_cmds; + } + } + + data = dev_read_prop(dev, "panel-exit-sequence", &len); + if (data) { + plat->off_cmds = calloc(1, sizeof(*plat->off_cmds)); + if (!plat->off_cmds) { + ret = -ENOMEM; + goto free_on_cmds; + } + + ret = rockchip_panel_parse_cmds(data, len, plat->off_cmds); + if (ret) { + printf("failed to parse panel exit sequence\n"); + goto free_cmds; + } + } + + return 0; + +free_cmds: + free(plat->off_cmds); +free_on_cmds: + free(plat->on_cmds); + return ret; +} + +static int rockchip_panel_probe(struct udevice *dev) +{ + struct rockchip_panel_priv *priv = dev_get_priv(dev); + int ret; + + ret = gpio_request_by_name(dev, "enable-gpios", 0, + &priv->enable_gpio, GPIOD_IS_OUT); + if (ret && ret != -ENOENT) { + printf("%s: Cannot get enable GPIO: %d\n", __func__, ret); + return ret; + } + + ret = gpio_request_by_name(dev, "reset-gpios", 0, + &priv->reset_gpio, GPIOD_IS_OUT); + if (ret && ret != -ENOENT) { + printf("%s: Cannot get reset GPIO: %d\n", __func__, ret); + return ret; + } + + ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev, + "backlight", &priv->backlight); + if (ret && ret != -ENOENT) { + printf("%s: Cannot get backlight: %d\n", __func__, ret); + return ret; + } + + ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev, + "power-supply", &priv->power_supply); + if (ret && ret != -ENOENT) { + printf("%s: Cannot get power supply: %d\n", __func__, ret); + return ret; + } + + return 0; +} + static const struct drm_display_mode auo_b125han03_mode = { .clock = 146900, .hdisplay = 1920, @@ -30,6 +384,11 @@ static const struct drm_display_mode auo_b125han03_mode = { .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, }; +static const struct rockchip_panel auo_b125han03_data = { + .funcs = &rockchip_panel_funcs, + .data = &auo_b125han03_mode, +}; + static const struct drm_display_mode lg_lp079qx1_sp0v_mode = { .clock = 200000, .hdisplay = 1536, @@ -44,153 +403,38 @@ static const struct drm_display_mode lg_lp079qx1_sp0v_mode = { .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, }; -static const struct rockchip_panel simple_panel_data = { - .funcs = &panel_simple_funcs, -}; - static const struct rockchip_panel lg_lp079qx1_sp0v_data = { - .funcs = &panel_simple_funcs, + .funcs = &rockchip_panel_funcs, .data = &lg_lp079qx1_sp0v_mode, }; -static const struct rockchip_panel auo_b125han03_data = { - .funcs = &panel_simple_funcs, - .data = &auo_b125han03_mode, +static const struct rockchip_panel rockchip_panel_data = { + .funcs = &rockchip_panel_funcs, }; -#endif - -#ifdef CONFIG_DRM_ROCKCHIP_DSI_PANEL -static const struct rockchip_panel simple_panel_dsi_data = { - .funcs = &rockchip_dsi_panel_funcs, -}; -#endif static const struct udevice_id rockchip_panel_ids[] = { -#ifdef CONFIG_DRM_ROCKCHIP_PANEL { - .compatible = "simple-panel", - .data = (ulong)&simple_panel_data, + .compatible = "auo,b125han03", + .data = (ulong)&auo_b125han03_data, }, { .compatible = "lg,lp079qx1-sp0v", .data = (ulong)&lg_lp079qx1_sp0v_data, }, { - .compatible = "auo,b125han03", - .data = (ulong)&auo_b125han03_data, - }, -#endif -#ifdef CONFIG_DRM_ROCKCHIP_DSI_PANEL - { + .compatible = "simple-panel", + .data = (ulong)&rockchip_panel_data, + }, { .compatible = "simple-panel-dsi", - .data = (ulong)&simple_panel_dsi_data, + .data = (ulong)&rockchip_panel_data, }, -#endif {} }; -static int rockchip_panel_probe(struct udevice *dev) -{ - return 0; -} - -static int rockchip_panel_bind(struct udevice *dev) -{ - return 0; -} - U_BOOT_DRIVER(rockchip_panel) = { .name = "rockchip_panel", .id = UCLASS_PANEL, .of_match = rockchip_panel_ids, - .bind = rockchip_panel_bind, - .probe = rockchip_panel_probe, + .ofdata_to_platdata = rockchip_panel_ofdata_to_platdata, + .probe = rockchip_panel_probe, + .priv_auto_alloc_size = sizeof(struct rockchip_panel_priv), + .platdata_auto_alloc_size = sizeof(struct rockchip_panel_plat), }; - -const struct drm_display_mode * -rockchip_get_display_mode_from_panel(struct display_state *state) -{ - struct panel_state *panel_state = &state->panel_state; - const struct rockchip_panel *panel = panel_state->panel; - - if (!panel || !panel->data) - return NULL; - - return (const struct drm_display_mode *)panel->data; -} - -int rockchip_panel_init(struct display_state *state) -{ - struct panel_state *panel_state = &state->panel_state; - const struct rockchip_panel *panel = panel_state->panel; - - if (!panel || !panel->funcs || !panel->funcs->init) { - printf("%s: failed to find panel init funcs\n", __func__); - return -ENODEV; - } - - return panel->funcs->init(state); -} - -void rockchip_panel_deinit(struct display_state *state) -{ - struct panel_state *panel_state = &state->panel_state; - const struct rockchip_panel *panel = panel_state->panel; - - if (!panel || !panel->funcs || !panel->funcs->deinit) { - printf("%s: failed to find panel deinit funcs\n", __func__); - return; - } - - panel->funcs->deinit(state); -} - -int rockchip_panel_prepare(struct display_state *state) -{ - struct panel_state *panel_state = &state->panel_state; - const struct rockchip_panel *panel = panel_state->panel; - - if (!panel || !panel->funcs || !panel->funcs->prepare) { - printf("%s: failed to find panel prepare funcs\n", __func__); - return -ENODEV; - } - - return panel->funcs->prepare(state); -} - -int rockchip_panel_unprepare(struct display_state *state) -{ - struct panel_state *panel_state = &state->panel_state; - const struct rockchip_panel *panel = panel_state->panel; - - if (!panel || !panel->funcs || !panel->funcs->unprepare) { - printf("%s: failed to find panel unprepare funcs\n", __func__); - return -ENODEV; - } - - return panel->funcs->unprepare(state); -} - -int rockchip_panel_enable(struct display_state *state) -{ - struct panel_state *panel_state = &state->panel_state; - const struct rockchip_panel *panel = panel_state->panel; - - if (!panel || !panel->funcs || !panel->funcs->enable) { - printf("%s: failed to find panel prepare funcs\n", __func__); - return -ENODEV; - } - - return panel->funcs->enable(state); -} - -int rockchip_panel_disable(struct display_state *state) -{ - struct panel_state *panel_state = &state->panel_state; - const struct rockchip_panel *panel = panel_state->panel; - - if (!panel || !panel->funcs || !panel->funcs->disable) { - printf("%s: failed to find panel disable funcs\n", __func__); - return -ENODEV; - } - - return panel->funcs->disable(state); -} diff --git a/drivers/video/drm/rockchip_panel.h b/drivers/video/drm/rockchip_panel.h index 1f4163ddff..c947c9e4c7 100644 --- a/drivers/video/drm/rockchip_panel.h +++ b/drivers/video/drm/rockchip_panel.h @@ -11,9 +11,9 @@ struct rockchip_panel_funcs { int (*init)(struct display_state *state); void (*deinit)(struct display_state *state); int (*prepare)(struct display_state *state); - int (*unprepare)(struct display_state *state); + void (*unprepare)(struct display_state *state); int (*enable)(struct display_state *state); - int (*disable)(struct display_state *state); + void (*disable)(struct display_state *state); }; struct rockchip_panel { @@ -21,20 +21,4 @@ struct rockchip_panel { const void *data; }; -const struct rockchip_panel *rockchip_get_panel(const void *blob, int node); -const struct drm_display_mode * -rockchip_get_display_mode_from_panel(struct display_state *state); -int rockchip_panel_init(struct display_state *state); -void rockchip_panel_deinit(struct display_state *state); -int rockchip_panel_enable(struct display_state *state); -int rockchip_panel_disable(struct display_state *state); -int rockchip_panel_prepare(struct display_state *state); -int rockchip_panel_unprepare(struct display_state *state); - -#ifdef CONFIG_DRM_ROCKCHIP_PANEL -extern const struct rockchip_panel_funcs panel_simple_funcs; -#endif -#ifdef CONFIG_DRM_ROCKCHIP_DSI_PANEL -extern const struct rockchip_panel_funcs rockchip_dsi_panel_funcs; -#endif #endif /* _ROCKCHIP_PANEL_H_ */