Commit e58e0ea5935cc4456f8f6f92763fdbd20ba750f1

Authored by Ye Li
1 parent a2fd185001

MLK-23964-16 video: Add video drivers for iMX8MM/iMX8MN display

Update mxsfb for LCD video driver, add mipi dsi driver,
ADV7535 and raydium-rm67191 panel drivers.

Signed-off-by: Ye Li <ye.li@nxp.com>
(cherry picked from commit 161c5785d2b8b3046bd673037d070fdbda61fb7c)

Showing 9 changed files with 2180 additions and 43 deletions Side-by-side Diff

drivers/video/Kconfig
... ... @@ -346,6 +346,15 @@
346 346 Say Y here if you want to enable support for Raydium RM68200
347 347 720x1280 DSI video mode panel.
348 348  
  349 +config VIDEO_LCD_RAYDIUM_RM67191
  350 + bool "RM67191 DSI LCD panel support"
  351 + depends on DM_VIDEO
  352 + select VIDEO_MIPI_DSI
  353 + default n
  354 + help
  355 + Say Y here if you want to enable support for Raydium RM68200
  356 + 1080x1920 DSI video mode panel.
  357 +
349 358 config VIDEO_LCD_SSD2828
350 359 bool "SSD2828 bridge chip"
351 360 default n
... ... @@ -793,6 +802,15 @@
793 802 help
794 803 Say Y here if you want to enable support for ITE IT6263
795 804 LVDS to HDMI connector, currently only support 1280x720P.
  805 +
  806 +config VIDEO_ADV7535
  807 + bool "ADV7535 MIPI DSI to HDMI connector"
  808 + depends on DM_VIDEO
  809 + select VIDEO_MIPI_DSI
  810 + default n
  811 + help
  812 + Say Y here if you want to enable support for ADI ADV7535
  813 + DSI to HDMI connector, currently only support 1920x1080.
796 814  
797 815 endmenu
drivers/video/Makefile
... ... @@ -54,7 +54,9 @@
54 54 obj-$(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM) += hitachi_tx18d42vm_lcd.o
55 55 obj-$(CONFIG_VIDEO_LCD_ORISETECH_OTM8009A) += orisetech_otm8009a.o
56 56 obj-$(CONFIG_VIDEO_LCD_RAYDIUM_RM68200) += raydium-rm68200.o
  57 +obj-$(CONFIG_VIDEO_LCD_RAYDIUM_RM67191) += raydium-rm67191.o
57 58 obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o
  59 +obj-$(CONFIG_VIDEO_ADV7535) += adv7535.o
58 60 obj-$(CONFIG_VIDEO_MB862xx) += mb862xx.o videomodes.o
59 61 obj-${CONFIG_VIDEO_MESON} += meson/
60 62 obj-${CONFIG_VIDEO_MIPI_DSI} += mipi_dsi.o
drivers/video/adv7535.c
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +/*
  3 + * Copyright 2019 NXP
  4 + *
  5 + */
  6 +
  7 +#include <common.h>
  8 +#include <dm.h>
  9 +#include <mipi_dsi.h>
  10 +#include <panel.h>
  11 +#include <asm/gpio.h>
  12 +#include <i2c.h>
  13 +#include <linux/err.h>
  14 +
  15 +struct adv7535_priv {
  16 + unsigned int addr;
  17 + unsigned int addr_cec;
  18 + unsigned int lanes;
  19 + enum mipi_dsi_pixel_format format;
  20 + unsigned long mode_flags;
  21 + struct udevice *cec_dev;
  22 +};
  23 +
  24 +static const struct display_timing default_timing = {
  25 + .pixelclock.typ = 148500000,
  26 + .hactive.typ = 1920,
  27 + .hfront_porch.typ = 88,
  28 + .hback_porch.typ = 148,
  29 + .hsync_len.typ = 44,
  30 + .vactive.typ = 1080,
  31 + .vfront_porch.typ = 4,
  32 + .vback_porch.typ = 36,
  33 + .vsync_len.typ = 5,
  34 +};
  35 +
  36 +static int adv7535_i2c_reg_write(struct udevice *dev, uint addr, uint mask, uint data)
  37 +{
  38 + uint8_t valb;
  39 + int err;
  40 +
  41 + if (mask != 0xff) {
  42 + err = dm_i2c_read(dev, addr, &valb, 1);
  43 + if (err)
  44 + return err;
  45 +
  46 + valb &= ~mask;
  47 + valb |= data;
  48 + } else {
  49 + valb = data;
  50 + }
  51 +
  52 + err = dm_i2c_write(dev, addr, &valb, 1);
  53 + return err;
  54 +}
  55 +
  56 +static int adv7535_i2c_reg_read(struct udevice *dev, uint8_t addr, uint8_t *data)
  57 +{
  58 + uint8_t valb;
  59 + int err;
  60 +
  61 + err = dm_i2c_read(dev, addr, &valb, 1);
  62 + if (err)
  63 + return err;
  64 +
  65 + *data = (int)valb;
  66 + return 0;
  67 +}
  68 +
  69 +static int adv7535_enable(struct udevice *dev)
  70 +{
  71 + struct adv7535_priv *priv = dev_get_priv(dev);
  72 + uint8_t val;
  73 +
  74 + adv7535_i2c_reg_read(dev, 0x00, &val);
  75 + debug("Chip revision: 0x%x (expected: 0x14)\n", val);
  76 + adv7535_i2c_reg_read(priv->cec_dev, 0x00, &val);
  77 + debug("Chip ID MSB: 0x%x (expected: 0x75)\n", val);
  78 + adv7535_i2c_reg_read(priv->cec_dev, 0x01, &val);
  79 + debug("Chip ID LSB: 0x%x (expected: 0x33)\n", val);
  80 +
  81 + /* Power */
  82 + adv7535_i2c_reg_write(dev, 0x41, 0xff, 0x10);
  83 + /* Initialisation (Fixed) Registers */
  84 + adv7535_i2c_reg_write(dev, 0x16, 0xff, 0x20);
  85 + adv7535_i2c_reg_write(dev, 0x9A, 0xff, 0xE0);
  86 + adv7535_i2c_reg_write(dev, 0xBA, 0xff, 0x70);
  87 + adv7535_i2c_reg_write(dev, 0xDE, 0xff, 0x82);
  88 + adv7535_i2c_reg_write(dev, 0xE4, 0xff, 0x40);
  89 + adv7535_i2c_reg_write(dev, 0xE5, 0xff, 0x80);
  90 + adv7535_i2c_reg_write(priv->cec_dev, 0x15, 0xff, 0xD0);
  91 + adv7535_i2c_reg_write(priv->cec_dev, 0x17, 0xff, 0xD0);
  92 + adv7535_i2c_reg_write(priv->cec_dev, 0x24, 0xff, 0x20);
  93 + adv7535_i2c_reg_write(priv->cec_dev, 0x57, 0xff, 0x11);
  94 + adv7535_i2c_reg_write(priv->cec_dev, 0x05, 0xff, 0xc8);
  95 +
  96 + /* 4 x DSI Lanes */
  97 + adv7535_i2c_reg_write(priv->cec_dev, 0x1C, 0xff, 0x40);
  98 +
  99 + /* DSI Pixel Clock Divider */
  100 + //adv7535_i2c_reg_write(priv->cec_dev, 0x16, 0xff, 0x0);
  101 + adv7535_i2c_reg_write(priv->cec_dev, 0x16, 0xff, 0x18);
  102 +
  103 + /* Enable Internal Timing Generator */
  104 + adv7535_i2c_reg_write(priv->cec_dev, 0x27, 0xff, 0xCB);
  105 + /* 1920 x 1080p 60Hz */
  106 + adv7535_i2c_reg_write(priv->cec_dev, 0x28, 0xff, 0x89); /* total width */
  107 + adv7535_i2c_reg_write(priv->cec_dev, 0x29, 0xff, 0x80); /* total width */
  108 + adv7535_i2c_reg_write(priv->cec_dev, 0x2A, 0xff, 0x02); /* hsync */
  109 + adv7535_i2c_reg_write(priv->cec_dev, 0x2B, 0xff, 0xC0); /* hsync */
  110 + adv7535_i2c_reg_write(priv->cec_dev, 0x2C, 0xff, 0x05); /* hfp */
  111 + adv7535_i2c_reg_write(priv->cec_dev, 0x2D, 0xff, 0x80); /* hfp */
  112 + adv7535_i2c_reg_write(priv->cec_dev, 0x2E, 0xff, 0x09); /* hbp */
  113 + adv7535_i2c_reg_write(priv->cec_dev, 0x2F, 0xff, 0x40); /* hbp */
  114 +
  115 + adv7535_i2c_reg_write(priv->cec_dev, 0x30, 0xff, 0x46); /* total height */
  116 + adv7535_i2c_reg_write(priv->cec_dev, 0x31, 0xff, 0x50); /* total height */
  117 + adv7535_i2c_reg_write(priv->cec_dev, 0x32, 0xff, 0x00); /* vsync */
  118 + adv7535_i2c_reg_write(priv->cec_dev, 0x33, 0xff, 0x50); /* vsync */
  119 + adv7535_i2c_reg_write(priv->cec_dev, 0x34, 0xff, 0x00); /* vfp */
  120 + adv7535_i2c_reg_write(priv->cec_dev, 0x35, 0xff, 0x40); /* vfp */
  121 + adv7535_i2c_reg_write(priv->cec_dev, 0x36, 0xff, 0x02); /* vbp */
  122 + adv7535_i2c_reg_write(priv->cec_dev, 0x37, 0xff, 0x40); /* vbp */
  123 +
  124 + /* Reset Internal Timing Generator */
  125 + adv7535_i2c_reg_write(priv->cec_dev, 0x27, 0xff, 0xCB);
  126 + adv7535_i2c_reg_write(priv->cec_dev, 0x27, 0xff, 0x8B);
  127 + adv7535_i2c_reg_write(priv->cec_dev, 0x27, 0xff, 0xCB);
  128 +
  129 + /* HDMI Output */
  130 + adv7535_i2c_reg_write(dev, 0xAF, 0xff, 0x16);
  131 + /* AVI Infoframe - RGB - 16-9 Aspect Ratio */
  132 + adv7535_i2c_reg_write(dev, 0x55, 0xff, 0x10);
  133 + //adv7535_i2c_reg_write(dev, 0x55, 0xff, 0x02);
  134 + adv7535_i2c_reg_write(dev, 0x56, 0xff, 0x28);
  135 + //adv7535_i2c_reg_write(dev, 0x56, 0xff, 0x0);
  136 +
  137 + /* GC Packet Enable */
  138 + adv7535_i2c_reg_write(dev, 0x40, 0xff, 0x80);
  139 + //adv7535_i2c_reg_write(dev, 0x40, 0xff, 0x0);
  140 + /* GC Colour Depth - 24 Bit */
  141 + adv7535_i2c_reg_write(dev, 0x4C, 0xff, 0x04);
  142 + //adv7535_i2c_reg_write(dev, 0x4C, 0xff, 0x0);
  143 + /* Down Dither Output Colour Depth - 8 Bit (default) */
  144 + adv7535_i2c_reg_write(dev, 0x49, 0xff, 0x00);
  145 +
  146 + /* set low refresh 1080p30 */
  147 + adv7535_i2c_reg_write(dev, 0x4A, 0xff, 0x80); /*should be 0x80 for 1080p60 and 0x8c for 1080p30*/
  148 +
  149 + /* HDMI Output Enable */
  150 + //adv7535_i2c_reg_write(priv->cec_dev, 0xbe, 0xff, 0x3c);
  151 + adv7535_i2c_reg_write(priv->cec_dev, 0xbe, 0xff, 0x3d);
  152 + adv7535_i2c_reg_write(priv->cec_dev, 0x03, 0xff, 0x89);
  153 +
  154 + return 0;
  155 +}
  156 +
  157 +static int adv7535_enable_backlight(struct udevice *dev)
  158 +{
  159 + struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev);
  160 + struct mipi_dsi_device *device = plat->device;
  161 + int ret;
  162 +
  163 + ret = mipi_dsi_attach(device);
  164 + if (ret < 0)
  165 + return ret;
  166 +
  167 + return 0;
  168 +}
  169 +
  170 +static int adv7535_get_display_timing(struct udevice *dev,
  171 + struct display_timing *timings)
  172 +{
  173 + struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev);
  174 + struct mipi_dsi_device *device = plat->device;
  175 + struct adv7535_priv *priv = dev_get_priv(dev);
  176 +
  177 + memcpy(timings, &default_timing, sizeof(*timings));
  178 +
  179 + /* fill characteristics of DSI data link */
  180 + if (device) {
  181 + device->lanes = priv->lanes;
  182 + device->format = priv->format;
  183 + device->mode_flags = priv->mode_flags;
  184 + }
  185 +
  186 + return 0;
  187 +}
  188 +
  189 +static int adv7535_probe(struct udevice *dev)
  190 +{
  191 + struct adv7535_priv *priv = dev_get_priv(dev);
  192 + int ret;
  193 +
  194 + debug("%s\n", __func__);
  195 +
  196 + priv->format = MIPI_DSI_FMT_RGB888;
  197 + priv->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
  198 + MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE,
  199 +
  200 + priv->addr = dev_read_addr(dev);
  201 + if (priv->addr == 0)
  202 + return -ENODEV;
  203 +
  204 + ret = dev_read_u32(dev, "adi,dsi-lanes", &priv->lanes);
  205 + if (ret) {
  206 + dev_err(dev, "Failed to get dsi-lanes property (%d)\n", ret);
  207 + return ret;
  208 + }
  209 +
  210 + if (priv->lanes < 1 || priv->lanes > 4) {
  211 + dev_err(dev, "Invalid dsi-lanes: %d\n", priv->lanes);
  212 + return -EINVAL;
  213 + }
  214 +
  215 + ret = dev_read_u32(dev, "adi,addr-cec", &priv->addr_cec);
  216 + if (ret) {
  217 + dev_err(dev, "Failed to get addr-cec property (%d)\n", ret);
  218 + return -EINVAL;
  219 + }
  220 +
  221 + ret = dm_i2c_probe(dev_get_parent(dev), priv->addr_cec, 0, &priv->cec_dev);
  222 + if (ret) {
  223 + dev_err(dev, "Can't find cec device id=0x%x\n", priv->addr_cec);
  224 + return -ENODEV;
  225 + }
  226 +
  227 + adv7535_enable(dev);
  228 +
  229 + return 0;
  230 +}
  231 +
  232 +static const struct panel_ops adv7535_ops = {
  233 + .enable_backlight = adv7535_enable_backlight,
  234 + .get_display_timing = adv7535_get_display_timing,
  235 +};
  236 +
  237 +static const struct udevice_id adv7535_ids[] = {
  238 + { .compatible = "adi,adv7533" },
  239 + { }
  240 +};
  241 +
  242 +U_BOOT_DRIVER(adv7535_mipi2hdmi) = {
  243 + .name = "adv7535_mipi2hdmi",
  244 + .id = UCLASS_PANEL,
  245 + .of_match = adv7535_ids,
  246 + .ops = &adv7535_ops,
  247 + .probe = adv7535_probe,
  248 + .platdata_auto_alloc_size = sizeof(struct mipi_dsi_panel_plat),
  249 + .priv_auto_alloc_size = sizeof(struct adv7535_priv),
  250 +};
drivers/video/imx/Kconfig
... ... @@ -48,4 +48,23 @@
48 48 select VIDEO_LINK
49 49 help
50 50 Support for HDMI on i.MX8MQ processors.
  51 +
  52 +config VIDEO_SEC_MIPI_DSI
  53 + bool
  54 + select VIDEO_MIPI_DSI
  55 + help
  56 + Enables the common driver code for the Samsung
  57 + MIPI DSI block found in SoCs from various vendors.
  58 + As this does not provide any functionality by itself (but
  59 + rather requires a SoC-specific glue driver to call it), it
  60 + can not be enabled from the configuration menu.
  61 +
  62 +config VIDEO_IMX_SEC_DSI
  63 + bool "Enable IMX SEC DSI video support"
  64 + select VIDEO_BRIDGE
  65 + select VIDEO_SEC_MIPI_DSI
  66 + select VIDEO_LINK
  67 + help
  68 + This option enables support DSI internal bridge which can be used on
  69 + devices which have DSI devices connected.
drivers/video/imx/Makefile
... ... @@ -7,5 +7,7 @@
7 7 obj-$(CONFIG_VIDEO_IMXDPUV1) += imxdpuv1.o imx8_dc.o
8 8 obj-$(CONFIG_VIDEO_IMX8_LVDS) += imx8_lvds.o
9 9 obj-$(CONFIG_VIDEO_IMX8M_DCSS) += imx8m_dcss.o
  10 +obj-$(CONFIG_VIDEO_SEC_MIPI_DSI) += sec_mipi_dsim.o
  11 +obj-$(CONFIG_VIDEO_IMX_SEC_DSI) += sec_dsim_imx.o
10 12 obj-y += hdmi/
drivers/video/imx/sec_dsim_imx.c
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +/*
  3 + * Copyright 2019 NXP
  4 + *
  5 + */
  6 +
  7 +#include <common.h>
  8 +#include <clk.h>
  9 +#include <dm.h>
  10 +#include <dsi_host.h>
  11 +#include <mipi_dsi.h>
  12 +#include <panel.h>
  13 +#include <reset.h>
  14 +#include <video.h>
  15 +#include <video_bridge.h>
  16 +#include <video_link.h>
  17 +#include <asm/io.h>
  18 +#include <asm/arch/gpio.h>
  19 +#include <dm/device-internal.h>
  20 +#include <linux/iopoll.h>
  21 +#include <linux/err.h>
  22 +#include <power/regulator.h>
  23 +#include <regmap.h>
  24 +#include <syscon.h>
  25 +
  26 +/* fixed phy ref clk rate */
  27 +#define PHY_REF_CLK 27000000
  28 +
  29 +struct imx_sec_dsim_priv {
  30 + struct mipi_dsi_device device;
  31 + void __iomem *base;
  32 + struct udevice *panel;
  33 + struct udevice *dsi_host;
  34 + struct reset_ctl_bulk soft_resetn;
  35 + struct reset_ctl_bulk clk_enable;
  36 + struct reset_ctl_bulk mipi_reset;
  37 +};
  38 +
  39 +static int sec_dsim_rstc_reset(struct reset_ctl_bulk *rstc, bool assert)
  40 +{
  41 + int ret;
  42 +
  43 + if (!rstc)
  44 + return 0;
  45 +
  46 + ret = assert ? reset_assert_bulk(rstc) :
  47 + reset_deassert_bulk(rstc);
  48 +
  49 + return ret;
  50 +}
  51 +
  52 +static int sec_dsim_of_parse_resets(struct udevice *dev)
  53 +{
  54 + int ret;
  55 + ofnode parent, child;
  56 + struct ofnode_phandle_args args;
  57 + struct reset_ctl_bulk rstc;
  58 + const char *compat;
  59 + uint32_t rstc_num = 0;
  60 +
  61 + struct imx_sec_dsim_priv *priv = dev_get_priv(dev);
  62 +
  63 + ret = dev_read_phandle_with_args(dev, "resets", "#reset-cells", 0,
  64 + 0, &args);
  65 + if (ret)
  66 + return ret;
  67 +
  68 + parent = args.node;
  69 + ofnode_for_each_subnode(child, parent) {
  70 + compat = ofnode_get_property(child, "compatible", NULL);
  71 + if (!compat)
  72 + continue;
  73 +
  74 + ret = reset_get_bulk_nodev(child, &rstc);
  75 + if (ret)
  76 + continue;
  77 +
  78 + if (!of_compat_cmp("dsi,soft-resetn", compat, 0)) {
  79 + priv->soft_resetn = rstc;
  80 + rstc_num++;
  81 + } else if (!of_compat_cmp("dsi,clk-enable", compat, 0)) {
  82 + priv->clk_enable = rstc;
  83 + rstc_num++;
  84 + } else if (!of_compat_cmp("dsi,mipi-reset", compat, 0)) {
  85 + priv->mipi_reset = rstc;
  86 + rstc_num++;
  87 + } else
  88 + dev_warn(dev, "invalid dsim reset node: %s\n", compat);
  89 + }
  90 +
  91 + if (!rstc_num) {
  92 + dev_err(dev, "no invalid reset control exists\n");
  93 + return -EINVAL;
  94 + }
  95 +
  96 + return 0;
  97 +}
  98 +
  99 +static int imx_sec_dsim_attach(struct udevice *dev)
  100 +{
  101 + struct imx_sec_dsim_priv *priv = dev_get_priv(dev);
  102 + struct mipi_dsi_device *device = &priv->device;
  103 + struct mipi_dsi_panel_plat *mplat;
  104 + struct display_timing timings;
  105 + int ret;
  106 +
  107 + priv->panel = video_link_get_next_device(dev);
  108 + if (!priv->panel ||
  109 + device_get_uclass_id(priv->panel) != UCLASS_PANEL) {
  110 + dev_err(dev, "get panel device error\n");
  111 + return -ENODEV;
  112 + }
  113 +
  114 + mplat = dev_get_platdata(priv->panel);
  115 + mplat->device = &priv->device;
  116 +
  117 + ret = video_link_get_display_timings(&timings);
  118 + if (ret) {
  119 + dev_err(dev, "decode display timing error %d\n", ret);
  120 + return ret;
  121 + }
  122 +
  123 + ret = uclass_get_device(UCLASS_DSI_HOST, 0, &priv->dsi_host);
  124 + if (ret) {
  125 + dev_err(dev, "No video dsi host detected %d\n", ret);
  126 + return ret;
  127 + }
  128 +
  129 + ret = dsi_host_init(priv->dsi_host, device, &timings, 4,
  130 + NULL);
  131 + if (ret) {
  132 + dev_err(dev, "failed to initialize mipi dsi host\n");
  133 + return ret;
  134 + }
  135 +
  136 + return 0;
  137 +}
  138 +
  139 +static int imx_sec_dsim_set_backlight(struct udevice *dev, int percent)
  140 +{
  141 + struct imx_sec_dsim_priv *priv = dev_get_priv(dev);
  142 + int ret;
  143 +
  144 + ret = panel_enable_backlight(priv->panel);
  145 + if (ret) {
  146 + dev_err(dev, "panel %s enable backlight error %d\n",
  147 + priv->panel->name, ret);
  148 + return ret;
  149 + }
  150 +
  151 + ret = dsi_host_enable(priv->dsi_host);
  152 + if (ret) {
  153 + dev_err(dev, "failed to enable mipi dsi host\n");
  154 + return ret;
  155 + }
  156 +
  157 + return 0;
  158 +}
  159 +
  160 +static int imx_sec_dsim_probe(struct udevice *dev)
  161 +{
  162 + struct imx_sec_dsim_priv *priv = dev_get_priv(dev);
  163 + struct mipi_dsi_device *device = &priv->device;
  164 + int ret;
  165 +
  166 + device->dev = dev;
  167 +
  168 + sec_dsim_of_parse_resets(dev);
  169 +
  170 + ret = sec_dsim_rstc_reset(&priv->soft_resetn, false);
  171 + if (ret) {
  172 + dev_err(dev, "deassert soft_resetn failed\n");
  173 + return ret;
  174 + }
  175 +
  176 + ret = sec_dsim_rstc_reset(&priv->clk_enable, true);
  177 + if (ret) {
  178 + dev_err(dev, "assert clk_enable failed\n");
  179 + return ret;
  180 + }
  181 +
  182 + ret = sec_dsim_rstc_reset(&priv->mipi_reset, false);
  183 + if (ret) {
  184 + dev_err(dev, "deassert mipi_reset failed\n");
  185 + return ret;
  186 + }
  187 +
  188 + return ret;
  189 +}
  190 +
  191 +static int imx_sec_dsim_remove(struct udevice *dev)
  192 +{
  193 + struct imx_sec_dsim_priv *priv = dev_get_priv(dev);
  194 + int ret;
  195 +
  196 + if (priv->panel)
  197 + device_remove(priv->panel, DM_REMOVE_NORMAL);
  198 +
  199 + ret = dsi_host_disable(priv->dsi_host);
  200 + if (ret) {
  201 + dev_err(dev, "failed to enable mipi dsi host\n");
  202 + return ret;
  203 + }
  204 +
  205 + return 0;
  206 +}
  207 +
  208 +struct video_bridge_ops imx_sec_dsim_ops = {
  209 + .attach = imx_sec_dsim_attach,
  210 + .set_backlight = imx_sec_dsim_set_backlight,
  211 +};
  212 +
  213 +static const struct udevice_id imx_sec_dsim_ids[] = {
  214 + { .compatible = "fsl,imx8mm-mipi-dsim" },
  215 + { .compatible = "fsl,imx8mn-mipi-dsim" },
  216 + { }
  217 +};
  218 +
  219 +U_BOOT_DRIVER(imx_sec_dsim) = {
  220 + .name = "imx_sec_dsim",
  221 + .id = UCLASS_VIDEO_BRIDGE,
  222 + .of_match = imx_sec_dsim_ids,
  223 + .bind = dm_scan_fdt_dev,
  224 + .remove = imx_sec_dsim_remove,
  225 + .probe = imx_sec_dsim_probe,
  226 + .ops = &imx_sec_dsim_ops,
  227 + .priv_auto_alloc_size = sizeof(struct imx_sec_dsim_priv),
  228 +};
drivers/video/imx/sec_mipi_dsim.c
Changes suppressed. Click to show
  1 +/*
  2 + * Copyright 2018 NXP
  3 + *
  4 + * SPDX-License-Identifier: GPL-2.0+
  5 + */
  6 +
  7 +#include <common.h>
  8 +#include <dm.h>
  9 +#include <asm/io.h>
  10 +#include <linux/err.h>
  11 +#include <asm/unaligned.h>
  12 +#include <asm/arch/clock.h>
  13 +#include <asm/arch/imx-regs.h>
  14 +#include <asm/arch/sys_proto.h>
  15 +#include <div64.h>
  16 +#include <video_bridge.h>
  17 +#include <panel.h>
  18 +#include <dsi_host.h>
  19 +#include <asm/arch/gpio.h>
  20 +#include <dm/device-internal.h>
  21 +
  22 +#define MIPI_FIFO_TIMEOUT 250000 /* 250ms */
  23 +
  24 +#define DRIVER_NAME "sec_mipi_dsim"
  25 +
  26 +/* dsim registers */
  27 +#define DSIM_VERSION 0x00
  28 +#define DSIM_STATUS 0x04
  29 +#define DSIM_RGB_STATUS 0x08
  30 +#define DSIM_SWRST 0x0c
  31 +#define DSIM_CLKCTRL 0x10
  32 +#define DSIM_TIMEOUT 0x14
  33 +#define DSIM_CONFIG 0x18
  34 +#define DSIM_ESCMODE 0x1c
  35 +#define DSIM_MDRESOL 0x20
  36 +#define DSIM_MVPORCH 0x24
  37 +#define DSIM_MHPORCH 0x28
  38 +#define DSIM_MSYNC 0x2c
  39 +#define DSIM_SDRESOL 0x30
  40 +#define DSIM_INTSRC 0x34
  41 +#define DSIM_INTMSK 0x38
  42 +
  43 +/* packet */
  44 +#define DSIM_PKTHDR 0x3c
  45 +#define DSIM_PAYLOAD 0x40
  46 +#define DSIM_RXFIFO 0x44
  47 +#define DSIM_FIFOTHLD 0x48
  48 +#define DSIM_FIFOCTRL 0x4c
  49 +#define DSIM_MEMACCHR 0x50
  50 +#define DSIM_MULTI_PKT 0x78
  51 +
  52 +/* pll control */
  53 +#define DSIM_PLLCTRL_1G 0x90
  54 +#define DSIM_PLLCTRL 0x94
  55 +#define DSIM_PLLCTRL1 0x98
  56 +#define DSIM_PLLCTRL2 0x9c
  57 +#define DSIM_PLLTMR 0xa0
  58 +
  59 +/* dphy */
  60 +#define DSIM_PHYTIMING 0xb4
  61 +#define DSIM_PHYTIMING1 0xb8
  62 +#define DSIM_PHYTIMING2 0xbc
  63 +
  64 +/* reg bit manipulation */
  65 +#define REG_MASK(e, s) (((1 << ((e) - (s) + 1)) - 1) << (s))
  66 +#define REG_PUT(x, e, s) (((x) << (s)) & REG_MASK(e, s))
  67 +#define REG_GET(x, e, s) (((x) & REG_MASK(e, s)) >> (s))
  68 +
  69 +/* register bit fields */
  70 +#define STATUS_PLLSTABLE BIT(31)
  71 +#define STATUS_SWRSTRLS BIT(20)
  72 +#define STATUS_TXREADYHSCLK BIT(10)
  73 +#define STATUS_ULPSCLK BIT(9)
  74 +#define STATUS_STOPSTATECLK BIT(8)
  75 +#define STATUS_GET_ULPSDAT(x) REG_GET(x, 7, 4)
  76 +#define STATUS_GET_STOPSTATEDAT(x) REG_GET(x, 3, 0)
  77 +
  78 +#define RGB_STATUS_CMDMODE_INSEL BIT(31)
  79 +#define RGB_STATUS_GET_RGBSTATE(x) REG_GET(x, 12, 0)
  80 +
  81 +#define CLKCTRL_TXREQUESTHSCLK BIT(31)
  82 +#define CLKCTRL_DPHY_SEL_1G BIT(29)
  83 +#define CLKCTRL_DPHY_SEL_1P5G (0x0 << 29)
  84 +#define CLKCTRL_ESCCLKEN BIT(28)
  85 +#define CLKCTRL_PLLBYPASS BIT(29)
  86 +#define CLKCTRL_BYTECLKSRC_DPHY_PLL REG_PUT(0, 26, 25)
  87 +#define CLKCTRL_BYTECLKEN BIT(24)
  88 +#define CLKCTRL_SET_LANEESCCLKEN(x) REG_PUT(x, 23, 19)
  89 +#define CLKCTRL_SET_ESCPRESCALER(x) REG_PUT(x, 15, 0)
  90 +
  91 +#define TIMEOUT_SET_BTAOUT(x) REG_PUT(x, 23, 16)
  92 +#define TIMEOUT_SET_LPDRTOUT(x) REG_PUT(x, 15, 0)
  93 +
  94 +#define CONFIG_NON_CONTINOUS_CLOCK_LANE BIT(31)
  95 +#define CONFIG_CLKLANE_STOP_START BIT(30)
  96 +#define CONFIG_MFLUSH_VS BIT(29)
  97 +#define CONFIG_EOT_R03 BIT(28)
  98 +#define CONFIG_SYNCINFORM BIT(27)
  99 +#define CONFIG_BURSTMODE BIT(26)
  100 +#define CONFIG_VIDEOMODE BIT(25)
  101 +#define CONFIG_AUTOMODE BIT(24)
  102 +#define CONFIG_HSEDISABLEMODE BIT(23)
  103 +#define CONFIG_HFPDISABLEMODE BIT(22)
  104 +#define CONFIG_HBPDISABLEMODE BIT(21)
  105 +#define CONFIG_HSADISABLEMODE BIT(20)
  106 +#define CONFIG_SET_MAINVC(x) REG_PUT(x, 19, 18)
  107 +#define CONFIG_SET_SUBVC(x) REG_PUT(x, 17, 16)
  108 +#define CONFIG_SET_MAINPIXFORMAT(x) REG_PUT(x, 14, 12)
  109 +#define CONFIG_SET_SUBPIXFORMAT(x) REG_PUT(x, 10, 8)
  110 +#define CONFIG_SET_NUMOFDATLANE(x) REG_PUT(x, 6, 5)
  111 +#define CONFIG_SET_LANEEN(x) REG_PUT(x, 4, 0)
  112 +
  113 +#define ESCMODE_SET_STOPSTATE_CNT(X) REG_PUT(x, 31, 21)
  114 +#define ESCMODE_FORCESTOPSTATE BIT(20)
  115 +#define ESCMODE_FORCEBTA BIT(16)
  116 +#define ESCMODE_CMDLPDT BIT(7)
  117 +#define ESCMODE_TXLPDT BIT(6)
  118 +#define ESCMODE_TXTRIGGERRST BIT(5)
  119 +
  120 +#define MDRESOL_MAINSTANDBY BIT(31)
  121 +#define MDRESOL_SET_MAINVRESOL(x) REG_PUT(x, 27, 16)
  122 +#define MDRESOL_SET_MAINHRESOL(x) REG_PUT(x, 11, 0)
  123 +
  124 +#define MVPORCH_SET_CMDALLOW(x) REG_PUT(x, 31, 28)
  125 +#define MVPORCH_SET_STABLEVFP(x) REG_PUT(x, 26, 16)
  126 +#define MVPORCH_SET_MAINVBP(x) REG_PUT(x, 10, 0)
  127 +
  128 +#define MHPORCH_SET_MAINHFP(x) REG_PUT(x, 31, 16)
  129 +#define MHPORCH_SET_MAINHBP(x) REG_PUT(x, 15, 0)
  130 +
  131 +#define MSYNC_SET_MAINVSA(x) REG_PUT(x, 31, 22)
  132 +#define MSYNC_SET_MAINHSA(x) REG_PUT(x, 15, 0)
  133 +
  134 +#define INTSRC_PLLSTABLE BIT(31)
  135 +#define INTSRC_SWRSTRELEASE BIT(30)
  136 +#define INTSRC_SFRPLFIFOEMPTY BIT(29)
  137 +#define INTSRC_SFRPHFIFOEMPTY BIT(28)
  138 +#define INTSRC_FRAMEDONE BIT(24)
  139 +#define INTSRC_LPDRTOUT BIT(21)
  140 +#define INTSRC_TATOUT BIT(20)
  141 +#define INTSRC_RXDATDONE BIT(18)
  142 +#define INTSRC_MASK (INTSRC_PLLSTABLE | \
  143 + INTSRC_SWRSTRELEASE | \
  144 + INTSRC_SFRPLFIFOEMPTY | \
  145 + INTSRC_SFRPHFIFOEMPTY | \
  146 + INTSRC_FRAMEDONE | \
  147 + INTSRC_LPDRTOUT | \
  148 + INTSRC_TATOUT | \
  149 + INTSRC_RXDATDONE)
  150 +
  151 +#define INTMSK_MSKPLLSTABLE BIT(31)
  152 +#define INTMSK_MSKSWRELEASE BIT(30)
  153 +#define INTMSK_MSKSFRPLFIFOEMPTY BIT(29)
  154 +#define INTMSK_MSKSFRPHFIFOEMPTY BIT(28)
  155 +#define INTMSK_MSKFRAMEDONE BIT(24)
  156 +#define INTMSK_MSKLPDRTOUT BIT(21)
  157 +#define INTMSK_MSKTATOUT BIT(20)
  158 +#define INTMSK_MSKRXDATDONE BIT(18)
  159 +
  160 +#define PKTHDR_SET_DATA1(x) REG_PUT(x, 23, 16)
  161 +#define PKTHDR_GET_DATA1(x) REG_GET(x, 23, 16)
  162 +#define PKTHDR_SET_DATA0(x) REG_PUT(x, 15, 8)
  163 +#define PKTHDR_GET_DATA0(x) REG_GET(x, 15, 8)
  164 +#define PKTHDR_GET_WC(x) REG_GET(x, 23, 8)
  165 +#define PKTHDR_SET_DI(x) REG_PUT(x, 7, 0)
  166 +#define PKTHDR_GET_DI(x) REG_GET(x, 7, 0)
  167 +#define PKTHDR_SET_DT(x) REG_PUT(x, 5, 0)
  168 +#define PKTHDR_GET_DT(x) REG_GET(x, 5, 0)
  169 +#define PKTHDR_SET_VC(x) REG_PUT(x, 7, 6)
  170 +#define PKTHDR_GET_VC(x) REG_GET(x, 7, 6)
  171 +
  172 +#define FIFOCTRL_FULLRX BIT(25)
  173 +#define FIFOCTRL_EMPTYRX BIT(24)
  174 +#define FIFOCTRL_FULLHSFR BIT(23)
  175 +#define FIFOCTRL_EMPTYHSFR BIT(22)
  176 +#define FIFOCTRL_FULLLSFR BIT(21)
  177 +#define FIFOCTRL_EMPTYLSFR BIT(20)
  178 +#define FIFOCTRL_FULLHMAIN BIT(11)
  179 +#define FIFOCTRL_EMPTYHMAIN BIT(10)
  180 +#define FIFOCTRL_FULLLMAIN BIT(9)
  181 +#define FIFOCTRL_EMPTYLMAIN BIT(8)
  182 +#define FIFOCTRL_NINITRX BIT(4)
  183 +#define FIFOCTRL_NINITSFR BIT(3)
  184 +#define FIFOCTRL_NINITI80 BIT(2)
  185 +#define FIFOCTRL_NINITSUB BIT(1)
  186 +#define FIFOCTRL_NINITMAIN BIT(0)
  187 +
  188 +#define PLLCTRL_DPDNSWAP_CLK BIT(25)
  189 +#define PLLCTRL_DPDNSWAP_DAT BIT(24)
  190 +#define PLLCTRL_PLLEN BIT(23)
  191 +#define PLLCTRL_SET_PMS(x) REG_PUT(x, 19, 1)
  192 +
  193 +#define PHYTIMING_SET_M_TLPXCTL(x) REG_PUT(x, 15, 8)
  194 +#define PHYTIMING_SET_M_THSEXITCTL(x) REG_PUT(x, 7, 0)
  195 +
  196 +#define PHYTIMING1_SET_M_TCLKPRPRCTL(x) REG_PUT(x, 31, 24)
  197 +#define PHYTIMING1_SET_M_TCLKZEROCTL(x) REG_PUT(x, 23, 16)
  198 +#define PHYTIMING1_SET_M_TCLKPOSTCTL(x) REG_PUT(x, 15, 8)
  199 +#define PHYTIMING1_SET_M_TCLKTRAILCTL(x) REG_PUT(x, 7, 0)
  200 +
  201 +#define PHYTIMING2_SET_M_THSPRPRCTL(x) REG_PUT(x, 23, 16)
  202 +#define PHYTIMING2_SET_M_THSZEROCTL(x) REG_PUT(x, 15, 8)
  203 +#define PHYTIMING2_SET_M_THSTRAILCTL(x) REG_PUT(x, 7, 0)
  204 +
  205 +#define dsim_read(dsim, reg) readl(dsim->base + reg)
  206 +#define dsim_write(dsim, val, reg) writel(val, dsim->base + reg)
  207 +
  208 +#define MAX_MAIN_HRESOL 2047
  209 +#define MAX_MAIN_VRESOL 2047
  210 +#define MAX_SUB_HRESOL 1024
  211 +#define MAX_SUB_VRESOL 1024
  212 +
  213 +/* in KHZ */
  214 +#define MAX_ESC_CLK_FREQ 20000
  215 +
  216 +/* dsim all irqs index */
  217 +#define PLLSTABLE 1
  218 +#define SWRSTRELEASE 2
  219 +#define SFRPLFIFOEMPTY 3
  220 +#define SFRPHFIFOEMPTY 4
  221 +#define SYNCOVERRIDE 5
  222 +#define BUSTURNOVER 6
  223 +#define FRAMEDONE 7
  224 +#define LPDRTOUT 8
  225 +#define TATOUT 9
  226 +#define RXDATDONE 10
  227 +#define RXTE 11
  228 +#define RXACK 12
  229 +#define ERRRXECC 13
  230 +#define ERRRXCRC 14
  231 +#define ERRESC3 15
  232 +#define ERRESC2 16
  233 +#define ERRESC1 17
  234 +#define ERRESC0 18
  235 +#define ERRSYNC3 19
  236 +#define ERRSYNC2 20
  237 +#define ERRSYNC1 21
  238 +#define ERRSYNC0 22
  239 +#define ERRCONTROL3 23
  240 +#define ERRCONTROL2 24
  241 +#define ERRCONTROL1 25
  242 +#define ERRCONTROL0 26
  243 +
  244 +/* Dispmix Control & GPR Registers */
  245 +#define DISPLAY_MIX_SFT_RSTN_CSR 0x00
  246 +#ifdef CONFIG_IMX8MN
  247 +#define MIPI_DSI_I_PRESETn_SFT_EN BIT(0) | BIT(1)
  248 +#else
  249 + #define MIPI_DSI_I_PRESETn_SFT_EN BIT(5)
  250 +#endif
  251 +#define DISPLAY_MIX_CLK_EN_CSR 0x04
  252 +
  253 +#ifdef CONFIG_IMX8MN
  254 +#define MIPI_DSI_PCLK_SFT_EN BIT(0)
  255 +#define MIPI_DSI_CLKREF_SFT_EN BIT(1)
  256 +#else
  257 + #define MIPI_DSI_PCLK_SFT_EN BIT(8)
  258 + #define MIPI_DSI_CLKREF_SFT_EN BIT(9)
  259 +#endif
  260 +#define GPR_MIPI_RESET_DIV 0x08
  261 + /* Clock & Data lanes reset: Active Low */
  262 + #define GPR_MIPI_S_RESETN BIT(16)
  263 + #define GPR_MIPI_M_RESETN BIT(17)
  264 +
  265 +#define PS2KHZ(ps) (1000000000UL / (ps))
  266 +
  267 +#define MIPI_HFP_PKT_OVERHEAD 6
  268 +#define MIPI_HBP_PKT_OVERHEAD 6
  269 +#define MIPI_HSA_PKT_OVERHEAD 6
  270 +
  271 +
  272 +/* DSIM PLL configuration from spec:
  273 + *
  274 + * Fout(DDR) = (M * Fin) / (P * 2^S), so Fout / Fin = M / (P * 2^S)
  275 + * Fin_pll = Fin / P (6 ~ 12 MHz)
  276 + * S: [2:0], M: [12:3], P: [18:13], so
  277 + * TODO: 'S' is in [0 ~ 3], 'M' is in, 'P' is in [1 ~ 33]
  278 + *
  279 + */
  280 +
  281 +struct sec_mipi_dsim {
  282 + void __iomem *base;
  283 +
  284 + /* kHz clocks */
  285 + uint64_t pix_clk;
  286 + uint64_t bit_clk;
  287 +
  288 + unsigned int lanes;
  289 + unsigned int channel; /* virtual channel */
  290 + enum mipi_dsi_pixel_format format;
  291 + unsigned long mode_flags;
  292 + unsigned int pms;
  293 + unsigned int p;
  294 + unsigned int m;
  295 + unsigned int s;
  296 +
  297 + struct mipi_dsi_device *device;
  298 + uint32_t max_data_lanes;
  299 + uint64_t max_data_rate;
  300 +
  301 + struct mipi_dsi_host dsi_host;
  302 +
  303 + struct display_timing timings;
  304 +};
  305 +
  306 +static int sec_mipi_dsim_wait_for_pkt_done(struct sec_mipi_dsim *dsim, unsigned long timeout)
  307 +{
  308 + uint32_t intsrc;
  309 +
  310 + do {
  311 + intsrc = dsim_read(dsim, DSIM_INTSRC);
  312 + if (intsrc & INTSRC_SFRPLFIFOEMPTY) {
  313 + dsim_write(dsim, INTSRC_SFRPLFIFOEMPTY, DSIM_INTSRC);
  314 + return 0;
  315 + }
  316 +
  317 + udelay(1);
  318 + } while (--timeout);
  319 +
  320 + return -ETIMEDOUT;
  321 +}
  322 +
  323 +static int sec_mipi_dsim_wait_for_hdr_done(struct sec_mipi_dsim *dsim, unsigned long timeout)
  324 +{
  325 + uint32_t intsrc;
  326 +
  327 + do {
  328 + intsrc = dsim_read(dsim, DSIM_INTSRC);
  329 + if (intsrc & INTSRC_SFRPHFIFOEMPTY) {
  330 + dsim_write(dsim, INTSRC_SFRPHFIFOEMPTY, DSIM_INTSRC);
  331 + return 0;
  332 + }
  333 +
  334 + udelay(1);
  335 + } while (--timeout);
  336 +
  337 + return -ETIMEDOUT;
  338 +}
  339 +
  340 +
  341 +static int sec_mipi_dsim_wait_for_rx_done(struct sec_mipi_dsim *dsim, unsigned long timeout)
  342 +{
  343 + uint32_t intsrc;
  344 +
  345 + do {
  346 + intsrc = dsim_read(dsim, DSIM_INTSRC);
  347 + if (intsrc & INTSRC_RXDATDONE) {
  348 + dsim_write(dsim, INTSRC_RXDATDONE, DSIM_INTSRC);
  349 + return 0;
  350 + }
  351 +
  352 + udelay(1);
  353 + } while (--timeout);
  354 +
  355 + return -ETIMEDOUT;
  356 +}
  357 +
  358 +static int sec_mipi_dsim_wait_pll_stable(struct sec_mipi_dsim *dsim)
  359 +{
  360 + uint32_t status;
  361 + ulong start;
  362 +
  363 + start = get_timer(0); /* Get current timestamp */
  364 +
  365 + do {
  366 + status = dsim_read(dsim, DSIM_STATUS);
  367 + if (status & STATUS_PLLSTABLE)
  368 + return 0;
  369 + } while (get_timer(0) < (start + 100)); /* Wait 100ms */
  370 +
  371 + return -ETIMEDOUT;
  372 +}
  373 +
  374 +static int sec_mipi_dsim_config_pll(struct sec_mipi_dsim *dsim)
  375 +{
  376 + int ret;
  377 + uint32_t pllctrl = 0, status, data_lanes_en, stop;
  378 +
  379 + dsim_write(dsim, 0x8000, DSIM_PLLTMR);
  380 +
  381 + /* TODO: config dp/dn swap if requires */
  382 +
  383 + pllctrl |= PLLCTRL_SET_PMS(dsim->pms) | PLLCTRL_PLLEN;
  384 + dsim_write(dsim, pllctrl, DSIM_PLLCTRL);
  385 +
  386 + ret = sec_mipi_dsim_wait_pll_stable(dsim);
  387 + if (ret) {
  388 + printf("wait for pll stable time out\n");
  389 + return ret;
  390 + }
  391 +
  392 + /* wait for clk & data lanes to go to stop state */
  393 + mdelay(1);
  394 +
  395 + data_lanes_en = (0x1 << dsim->lanes) - 1;
  396 + status = dsim_read(dsim, DSIM_STATUS);
  397 + if (!(status & STATUS_STOPSTATECLK)) {
  398 + printf("clock is not in stop state\n");
  399 + return -EBUSY;
  400 + }
  401 +
  402 + stop = STATUS_GET_STOPSTATEDAT(status);
  403 + if ((stop & data_lanes_en) != data_lanes_en) {
  404 + printf("one or more data lanes is not in stop state\n");
  405 + return -EBUSY;
  406 + }
  407 +
  408 + return 0;
  409 +}
  410 +
  411 +static void sec_mipi_dsim_set_main_mode(struct sec_mipi_dsim *dsim)
  412 +{
  413 + uint32_t bpp, hfp_wc, hbp_wc, hsa_wc, wc;
  414 + uint32_t mdresol = 0, mvporch = 0, mhporch = 0, msync = 0;
  415 + struct display_timing *timings = &dsim->timings;
  416 +
  417 + mdresol |= MDRESOL_SET_MAINVRESOL(timings->vactive.typ) |
  418 + MDRESOL_SET_MAINHRESOL(timings->hactive.typ);
  419 + dsim_write(dsim, mdresol, DSIM_MDRESOL);
  420 +
  421 + mvporch |= MVPORCH_SET_MAINVBP(timings->vback_porch.typ) |
  422 + MVPORCH_SET_STABLEVFP(timings->vfront_porch.typ) |
  423 + MVPORCH_SET_CMDALLOW(0x0);
  424 + dsim_write(dsim, mvporch, DSIM_MVPORCH);
  425 +
  426 + bpp = mipi_dsi_pixel_format_to_bpp(dsim->format);
  427 +
  428 +
  429 + wc = DIV_ROUND_UP(timings->hfront_porch.typ* (bpp >> 3),
  430 + dsim->lanes);
  431 + hfp_wc = wc > MIPI_HFP_PKT_OVERHEAD ?
  432 + wc - MIPI_HFP_PKT_OVERHEAD : timings->hfront_porch.typ;
  433 + wc = DIV_ROUND_UP(timings->hback_porch.typ * (bpp >> 3),
  434 + dsim->lanes);
  435 + hbp_wc = wc > MIPI_HBP_PKT_OVERHEAD ?
  436 + wc - MIPI_HBP_PKT_OVERHEAD : timings->hback_porch.typ;
  437 +
  438 + mhporch |= MHPORCH_SET_MAINHFP(hfp_wc) |
  439 + MHPORCH_SET_MAINHBP(hbp_wc);
  440 +
  441 + dsim_write(dsim, mhporch, DSIM_MHPORCH);
  442 +
  443 + wc = DIV_ROUND_UP(timings->hsync_len.typ * (bpp >> 3),
  444 + dsim->lanes);
  445 + hsa_wc = wc > MIPI_HSA_PKT_OVERHEAD ?
  446 + wc - MIPI_HSA_PKT_OVERHEAD : timings->hsync_len.typ;
  447 +
  448 + msync |= MSYNC_SET_MAINVSA(timings->vsync_len.typ) |
  449 + MSYNC_SET_MAINHSA(hsa_wc);
  450 +
  451 + debug("hfp_wc %u hbp_wc %u hsa_wc %u\n", hfp_wc, hbp_wc, hsa_wc);
  452 +
  453 + dsim_write(dsim, msync, DSIM_MSYNC);
  454 +}
  455 +
  456 +static void sec_mipi_dsim_config_dpi(struct sec_mipi_dsim *dsim)
  457 +{
  458 + uint32_t config = 0, rgb_status = 0, data_lanes_en;
  459 +
  460 + if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO)
  461 + rgb_status &= ~RGB_STATUS_CMDMODE_INSEL;
  462 + else
  463 + rgb_status |= RGB_STATUS_CMDMODE_INSEL;
  464 +
  465 + dsim_write(dsim, rgb_status, DSIM_RGB_STATUS);
  466 +
  467 + if (dsim->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
  468 + config |= CONFIG_CLKLANE_STOP_START;
  469 +
  470 + if (dsim->mode_flags & MIPI_DSI_MODE_VSYNC_FLUSH)
  471 + config |= CONFIG_MFLUSH_VS;
  472 +
  473 + /* disable EoT packets in HS mode */
  474 + if (dsim->mode_flags & MIPI_DSI_MODE_EOT_PACKET)
  475 + config |= CONFIG_EOT_R03;
  476 +
  477 + if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO) {
  478 + config |= CONFIG_VIDEOMODE;
  479 +
  480 + if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
  481 + config |= CONFIG_BURSTMODE;
  482 +
  483 + else if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
  484 + config |= CONFIG_SYNCINFORM;
  485 +
  486 + if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_AUTO_VERT)
  487 + config |= CONFIG_AUTOMODE;
  488 +
  489 + if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_HSE)
  490 + config |= CONFIG_HSEDISABLEMODE;
  491 +
  492 + if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_HFP)
  493 + config |= CONFIG_HFPDISABLEMODE;
  494 +
  495 + if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_HBP)
  496 + config |= CONFIG_HBPDISABLEMODE;
  497 +
  498 + if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_HSA)
  499 + config |= CONFIG_HSADISABLEMODE;
  500 + }
  501 +
  502 + config |= CONFIG_SET_MAINVC(dsim->channel);
  503 +
  504 + if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO) {
  505 + switch (dsim->format) {
  506 + case MIPI_DSI_FMT_RGB565:
  507 + config |= CONFIG_SET_MAINPIXFORMAT(0x4);
  508 + break;
  509 + case MIPI_DSI_FMT_RGB666_PACKED:
  510 + config |= CONFIG_SET_MAINPIXFORMAT(0x5);
  511 + break;
  512 + case MIPI_DSI_FMT_RGB666:
  513 + config |= CONFIG_SET_MAINPIXFORMAT(0x6);
  514 + break;
  515 + case MIPI_DSI_FMT_RGB888:
  516 + config |= CONFIG_SET_MAINPIXFORMAT(0x7);
  517 + break;
  518 + default:
  519 + config |= CONFIG_SET_MAINPIXFORMAT(0x7);
  520 + break;
  521 + }
  522 + }
  523 +
  524 + /* config data lanes number and enable lanes */
  525 + data_lanes_en = (0x1 << dsim->lanes) - 1;
  526 + config |= CONFIG_SET_NUMOFDATLANE(dsim->lanes - 1);
  527 + config |= CONFIG_SET_LANEEN(0x1 | data_lanes_en << 1);
  528 +
  529 + debug("DSIM config 0x%x\n", config);
  530 +
  531 + dsim_write(dsim, config, DSIM_CONFIG);
  532 +}
  533 +
  534 +static void sec_mipi_dsim_config_cmd_lpm(struct sec_mipi_dsim *dsim,
  535 + bool enable)
  536 +{
  537 + uint32_t escmode;
  538 +
  539 + escmode = dsim_read(dsim, DSIM_ESCMODE);
  540 +
  541 + if (enable)
  542 + escmode |= ESCMODE_CMDLPDT;
  543 + else
  544 + escmode &= ~ESCMODE_CMDLPDT;
  545 +
  546 + dsim_write(dsim, escmode, DSIM_ESCMODE);
  547 +}
  548 +
  549 +static void sec_mipi_dsim_config_dphy(struct sec_mipi_dsim *dsim)
  550 +{
  551 + uint32_t phytiming = 0, phytiming1 = 0, phytiming2 = 0, timeout = 0;
  552 +
  553 + /* TODO: add a PHY timing table arranged by the pll Fout */
  554 +
  555 + phytiming |= PHYTIMING_SET_M_TLPXCTL(6) |
  556 + PHYTIMING_SET_M_THSEXITCTL(11);
  557 + dsim_write(dsim, phytiming, DSIM_PHYTIMING);
  558 +
  559 + phytiming1 |= PHYTIMING1_SET_M_TCLKPRPRCTL(7) |
  560 + PHYTIMING1_SET_M_TCLKZEROCTL(38) |
  561 + PHYTIMING1_SET_M_TCLKPOSTCTL(13) |
  562 + PHYTIMING1_SET_M_TCLKTRAILCTL(8);
  563 + dsim_write(dsim, phytiming1, DSIM_PHYTIMING1);
  564 +
  565 + phytiming2 |= PHYTIMING2_SET_M_THSPRPRCTL(8) |
  566 + PHYTIMING2_SET_M_THSZEROCTL(13) |
  567 + PHYTIMING2_SET_M_THSTRAILCTL(11);
  568 + dsim_write(dsim, phytiming2, DSIM_PHYTIMING2);
  569 +
  570 + timeout |= TIMEOUT_SET_BTAOUT(0xf) |
  571 + TIMEOUT_SET_LPDRTOUT(0xf);
  572 + dsim_write(dsim, 0xf000f, DSIM_TIMEOUT);
  573 +}
  574 +
  575 +static void sec_mipi_dsim_write_pl_to_sfr_fifo(struct sec_mipi_dsim *dsim,
  576 + const void *payload,
  577 + size_t length)
  578 +{
  579 + uint32_t pl_data;
  580 +
  581 + if (!length)
  582 + return;
  583 +
  584 + while (length >= 4) {
  585 + pl_data = get_unaligned_le32(payload);
  586 + dsim_write(dsim, pl_data, DSIM_PAYLOAD);
  587 + payload += 4;
  588 + length -= 4;
  589 + }
  590 +
  591 + pl_data = 0;
  592 + switch (length) {
  593 + case 3:
  594 + pl_data |= ((u8 *)payload)[2] << 16;
  595 + case 2:
  596 + pl_data |= ((u8 *)payload)[1] << 8;
  597 + case 1:
  598 + pl_data |= ((u8 *)payload)[0];
  599 + dsim_write(dsim, pl_data, DSIM_PAYLOAD);
  600 + break;
  601 + }
  602 +}
  603 +
  604 +static void sec_mipi_dsim_write_ph_to_sfr_fifo(struct sec_mipi_dsim *dsim,
  605 + void *header,
  606 + bool use_lpm)
  607 +{
  608 + uint32_t pkthdr;
  609 +
  610 + pkthdr = PKTHDR_SET_DATA1(((u8 *)header)[2]) | /* WC MSB */
  611 + PKTHDR_SET_DATA0(((u8 *)header)[1]) | /* WC LSB */
  612 + PKTHDR_SET_DI(((u8 *)header)[0]); /* Data ID */
  613 +
  614 + dsim_write(dsim, pkthdr, DSIM_PKTHDR);
  615 +}
  616 +
  617 +static int sec_mipi_dsim_read_pl_from_sfr_fifo(struct sec_mipi_dsim *dsim,
  618 + void *payload,
  619 + size_t length)
  620 +{
  621 + uint8_t data_type;
  622 + uint16_t word_count = 0;
  623 + uint32_t fifoctrl, ph, pl;
  624 +
  625 + fifoctrl = dsim_read(dsim, DSIM_FIFOCTRL);
  626 +
  627 + if (WARN_ON(fifoctrl & FIFOCTRL_EMPTYRX))
  628 + return -EINVAL;
  629 +
  630 + ph = dsim_read(dsim, DSIM_RXFIFO);
  631 + data_type = PKTHDR_GET_DT(ph);
  632 + switch (data_type) {
  633 + case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
  634 + dev_err(dsim->dev, "peripheral report error: (0-7)%x, (8-15)%x\n",
  635 + PKTHDR_GET_DATA0(ph), PKTHDR_GET_DATA1(ph));
  636 + return -EPROTO;
  637 + case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
  638 + case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
  639 + if (!WARN_ON(length < 2)) {
  640 + ((u8 *)payload)[1] = PKTHDR_GET_DATA1(ph);
  641 + word_count++;
  642 + }
  643 + /* fall through */
  644 + case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
  645 + case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
  646 + ((u8 *)payload)[0] = PKTHDR_GET_DATA0(ph);
  647 + word_count++;
  648 + length = word_count;
  649 + break;
  650 + case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
  651 + case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
  652 + word_count = PKTHDR_GET_WC(ph);
  653 + if (word_count > length) {
  654 + dev_err(dsim->dev, "invalid receive buffer length\n");
  655 + return -EINVAL;
  656 + }
  657 +
  658 + length = word_count;
  659 +
  660 + while (word_count >= 4) {
  661 + pl = dsim_read(dsim, DSIM_RXFIFO);
  662 + ((u8 *)payload)[0] = pl & 0xff;
  663 + ((u8 *)payload)[1] = (pl >> 8) & 0xff;
  664 + ((u8 *)payload)[2] = (pl >> 16) & 0xff;
  665 + ((u8 *)payload)[3] = (pl >> 24) & 0xff;
  666 + payload += 4;
  667 + word_count -= 4;
  668 + }
  669 +
  670 + if (word_count > 0) {
  671 + pl = dsim_read(dsim, DSIM_RXFIFO);
  672 +
  673 + switch (word_count) {
  674 + case 3:
  675 + ((u8 *)payload)[2] = (pl >> 16) & 0xff;
  676 + case 2:
  677 + ((u8 *)payload)[1] = (pl >> 8) & 0xff;
  678 + case 1:
  679 + ((u8 *)payload)[0] = pl & 0xff;
  680 + break;
  681 + }
  682 + }
  683 +
  684 + break;
  685 + default:
  686 + return -EINVAL;
  687 + }
  688 +
  689 + return length;
  690 +}
  691 +
  692 +static void sec_mipi_dsim_init_fifo_pointers(struct sec_mipi_dsim *dsim)
  693 +{
  694 + uint32_t fifoctrl, fifo_ptrs;
  695 +
  696 + fifoctrl = dsim_read(dsim, DSIM_FIFOCTRL);
  697 +
  698 + fifo_ptrs = FIFOCTRL_NINITRX |
  699 + FIFOCTRL_NINITSFR |
  700 + FIFOCTRL_NINITI80 |
  701 + FIFOCTRL_NINITSUB |
  702 + FIFOCTRL_NINITMAIN;
  703 +
  704 + fifoctrl &= ~fifo_ptrs;
  705 + dsim_write(dsim, fifoctrl, DSIM_FIFOCTRL);
  706 + udelay(500);
  707 +
  708 + fifoctrl |= fifo_ptrs;
  709 + dsim_write(dsim, fifoctrl, DSIM_FIFOCTRL);
  710 + udelay(500);
  711 +}
  712 +
  713 +
  714 +static void sec_mipi_dsim_config_clkctrl(struct sec_mipi_dsim *dsim)
  715 +{
  716 + uint32_t clkctrl = 0, data_lanes_en;
  717 + uint64_t byte_clk, esc_prescaler;
  718 +
  719 + clkctrl |= CLKCTRL_TXREQUESTHSCLK;
  720 +
  721 + /* using 1.5Gbps PHY */
  722 + clkctrl |= CLKCTRL_DPHY_SEL_1P5G;
  723 +
  724 + clkctrl |= CLKCTRL_ESCCLKEN;
  725 +
  726 + clkctrl &= ~CLKCTRL_PLLBYPASS;
  727 +
  728 + clkctrl |= CLKCTRL_BYTECLKSRC_DPHY_PLL;
  729 +
  730 + clkctrl |= CLKCTRL_BYTECLKEN;
  731 +
  732 + data_lanes_en = (0x1 << dsim->lanes) - 1;
  733 + clkctrl |= CLKCTRL_SET_LANEESCCLKEN(0x1 | data_lanes_en << 1);
  734 +
  735 + /* calculate esc prescaler from byte clock:
  736 + * EscClk = ByteClk / EscPrescaler;
  737 + */
  738 + byte_clk = dsim->bit_clk >> 3;
  739 + esc_prescaler = DIV_ROUND_UP_ULL(byte_clk, MAX_ESC_CLK_FREQ);
  740 +
  741 + clkctrl |= CLKCTRL_SET_ESCPRESCALER(esc_prescaler);
  742 +
  743 + debug("DSIM clkctrl 0x%x\n", clkctrl);
  744 +
  745 + dsim_write(dsim, clkctrl, DSIM_CLKCTRL);
  746 +}
  747 +
  748 +static void sec_mipi_dsim_set_standby(struct sec_mipi_dsim *dsim,
  749 + bool standby)
  750 +{
  751 + uint32_t mdresol = 0;
  752 +
  753 + mdresol = dsim_read(dsim, DSIM_MDRESOL);
  754 +
  755 + if (standby)
  756 + mdresol |= MDRESOL_MAINSTANDBY;
  757 + else
  758 + mdresol &= ~MDRESOL_MAINSTANDBY;
  759 +
  760 + dsim_write(dsim, mdresol, DSIM_MDRESOL);
  761 +}
  762 +
  763 +static void sec_mipi_dsim_disable_clkctrl(struct sec_mipi_dsim *dsim)
  764 +{
  765 + uint32_t clkctrl;
  766 +
  767 + clkctrl = dsim_read(dsim, DSIM_CLKCTRL);
  768 +
  769 + clkctrl &= ~CLKCTRL_TXREQUESTHSCLK;
  770 +
  771 + clkctrl &= ~CLKCTRL_ESCCLKEN;
  772 +
  773 + clkctrl &= ~CLKCTRL_BYTECLKEN;
  774 +
  775 + dsim_write(dsim, clkctrl, DSIM_CLKCTRL);
  776 +}
  777 +
  778 +static void sec_mipi_dsim_disable_pll(struct sec_mipi_dsim *dsim)
  779 +{
  780 + uint32_t pllctrl;
  781 +
  782 + pllctrl = dsim_read(dsim, DSIM_PLLCTRL);
  783 +
  784 + pllctrl &= ~PLLCTRL_PLLEN;
  785 +
  786 + dsim_write(dsim, pllctrl, DSIM_PLLCTRL);
  787 +}
  788 +
  789 +static inline struct sec_mipi_dsim *host_to_dsi(struct mipi_dsi_host *host)
  790 +{
  791 + return container_of(host, struct sec_mipi_dsim, dsi_host);
  792 +}
  793 +
  794 +static int sec_mipi_dsim_bridge_clk_set(struct sec_mipi_dsim *dsim_host)
  795 +{
  796 + int bpp;
  797 + uint64_t pix_clk, bit_clk;
  798 +
  799 + bpp = mipi_dsi_pixel_format_to_bpp(dsim_host->format);
  800 + if (bpp < 0)
  801 + return -EINVAL;
  802 +
  803 + pix_clk = dsim_host->timings.pixelclock.typ;
  804 + bit_clk = DIV_ROUND_UP_ULL(pix_clk * bpp, dsim_host->lanes);
  805 +
  806 +#if 0
  807 + if (bit_clk > dsim_host->max_data_rate) {
  808 + printf("request bit clk freq exceeds lane's maximum value\n");
  809 + return -EINVAL;
  810 + }
  811 +#endif
  812 +
  813 + dsim_host->pix_clk = DIV_ROUND_UP_ULL(pix_clk, 1000);
  814 + dsim_host->bit_clk = DIV_ROUND_UP_ULL(bit_clk, 1000);
  815 +
  816 + if (dsim_host->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
  817 + /* TODO: add PMS calculate and check
  818 + * Only support '1080p@60Hz' for now,
  819 + * add other modes support later
  820 + */
  821 + dsim_host->pms = 0x4210;
  822 + }
  823 +
  824 + debug("%s: bitclk %llu pixclk %llu\n", __func__, dsim_host->bit_clk, dsim_host->pix_clk);
  825 +
  826 + return 0;
  827 +}
  828 +
  829 +static int sec_mipi_dsim_bridge_prepare(struct sec_mipi_dsim *dsim_host)
  830 +{
  831 + int ret;
  832 +
  833 + /* At this moment, the dsim bridge's preceding encoder has
  834 + * already been enabled. So the dsim can be configed here
  835 + */
  836 +
  837 + /* config main display mode */
  838 + sec_mipi_dsim_set_main_mode(dsim_host);
  839 +
  840 + /* config dsim dpi */
  841 + sec_mipi_dsim_config_dpi(dsim_host);
  842 +
  843 + /* config dsim pll */
  844 + ret = sec_mipi_dsim_config_pll(dsim_host);
  845 + if (ret) {
  846 + printf("dsim pll config failed: %d\n", ret);
  847 + return ret;
  848 + }
  849 +
  850 + /* config dphy timings */
  851 + sec_mipi_dsim_config_dphy(dsim_host);
  852 +
  853 + sec_mipi_dsim_init_fifo_pointers(dsim_host);
  854 +
  855 + /* config esc clock, byte clock and etc */
  856 + sec_mipi_dsim_config_clkctrl(dsim_host);
  857 +
  858 + /* enable data transfer of dsim */
  859 + sec_mipi_dsim_set_standby(dsim_host, true);
  860 +
  861 + return 0;
  862 +}
  863 +
  864 +static int sec_mipi_dsim_host_attach(struct mipi_dsi_host *host,
  865 + struct mipi_dsi_device *device)
  866 +{
  867 + struct sec_mipi_dsim *dsi = host_to_dsi(host);
  868 +
  869 + if (!device->lanes || device->lanes > dsi->max_data_lanes) {
  870 + printf("invalid data lanes number\n");
  871 + return -EINVAL;
  872 + }
  873 +
  874 + if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO) ||
  875 + !((device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) ||
  876 + (device->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE))) {
  877 + printf("unsupported dsi mode\n");
  878 + return -EINVAL;
  879 + }
  880 +
  881 + if (device->format != MIPI_DSI_FMT_RGB888 &&
  882 + device->format != MIPI_DSI_FMT_RGB565 &&
  883 + device->format != MIPI_DSI_FMT_RGB666 &&
  884 + device->format != MIPI_DSI_FMT_RGB666_PACKED) {
  885 + printf("unsupported pixel format: %#x\n", device->format);
  886 + return -EINVAL;
  887 + }
  888 +
  889 + dsi->lanes = device->lanes;
  890 + dsi->channel = device->channel;
  891 + dsi->format = device->format;
  892 + dsi->mode_flags = device->mode_flags;
  893 +
  894 + debug("lanes %u, channel %u, format 0x%x, mode_flags 0x%lx\n", dsi->lanes,
  895 + dsi->channel, dsi->format, dsi->mode_flags);
  896 +
  897 + sec_mipi_dsim_bridge_clk_set(dsi);
  898 + sec_mipi_dsim_bridge_prepare(dsi);
  899 +
  900 + return 0;
  901 +}
  902 +
  903 +static ssize_t sec_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
  904 + const struct mipi_dsi_msg *msg)
  905 +{
  906 + struct sec_mipi_dsim *dsim = host_to_dsi(host);
  907 + int ret, nb_bytes;
  908 + bool use_lpm;
  909 + struct mipi_dsi_packet packet;
  910 +
  911 +#ifdef DEBUG
  912 + int i = 0;
  913 + u8 *p = msg->tx_buf;
  914 +
  915 + printf("sec_mipi_dsi_host_transfer\n");
  916 + for (i; i < msg->tx_len; i++) {
  917 + printf("0x%.2x ", *(u8 *)p);
  918 + p++;
  919 + }
  920 + printf("\n");
  921 +#endif
  922 +
  923 + ret = mipi_dsi_create_packet(&packet, msg);
  924 + if (ret) {
  925 + dev_err(dsim->dev, "failed to create dsi packet: %d\n", ret);
  926 + return ret;
  927 + }
  928 +
  929 + /* config LPM for CMD TX */
  930 + use_lpm = msg->flags & MIPI_DSI_MSG_USE_LPM ? true : false;
  931 + sec_mipi_dsim_config_cmd_lpm(dsim, use_lpm);
  932 +
  933 + if (packet.payload_length) { /* Long Packet case */
  934 + /* write packet payload */
  935 + sec_mipi_dsim_write_pl_to_sfr_fifo(dsim,
  936 + packet.payload,
  937 + packet.payload_length);
  938 +
  939 + /* write packet header */
  940 + sec_mipi_dsim_write_ph_to_sfr_fifo(dsim,
  941 + packet.header,
  942 + use_lpm);
  943 +
  944 + ret = sec_mipi_dsim_wait_for_pkt_done(dsim, MIPI_FIFO_TIMEOUT);
  945 + if (ret) {
  946 + dev_err(dsim->dev, "wait tx done timeout!\n");
  947 + return -EBUSY;
  948 + }
  949 + } else {
  950 + /* write packet header */
  951 + sec_mipi_dsim_write_ph_to_sfr_fifo(dsim,
  952 + packet.header,
  953 + use_lpm);
  954 +
  955 + ret = sec_mipi_dsim_wait_for_hdr_done(dsim, MIPI_FIFO_TIMEOUT);
  956 + if (ret) {
  957 + dev_err(dsim->dev, "wait pkthdr tx done time out\n");
  958 + return -EBUSY;
  959 + }
  960 + }
  961 +
  962 + /* read packet payload */
  963 + if (unlikely(msg->rx_buf)) {
  964 + ret = sec_mipi_dsim_wait_for_rx_done(dsim,
  965 + MIPI_FIFO_TIMEOUT);
  966 + if (ret) {
  967 + dev_err(dsim->dev, "wait rx done time out\n");
  968 + return -EBUSY;
  969 + }
  970 +
  971 + ret = sec_mipi_dsim_read_pl_from_sfr_fifo(dsim,
  972 + msg->rx_buf,
  973 + msg->rx_len);
  974 + if (ret < 0)
  975 + return ret;
  976 + nb_bytes = msg->rx_len;
  977 + } else {
  978 + nb_bytes = packet.size;
  979 + }
  980 +
  981 + return nb_bytes;
  982 +
  983 +}
  984 +
  985 +
  986 +static const struct mipi_dsi_host_ops sec_mipi_dsim_host_ops = {
  987 + .attach = sec_mipi_dsim_host_attach,
  988 + .transfer = sec_mipi_dsi_host_transfer,
  989 +};
  990 +
  991 +static int sec_mipi_dsim_init(struct udevice *dev,
  992 + struct mipi_dsi_device *device,
  993 + struct display_timing *timings,
  994 + unsigned int max_data_lanes,
  995 + const struct mipi_dsi_phy_ops *phy_ops)
  996 +{
  997 + struct sec_mipi_dsim *dsi = dev_get_priv(dev);
  998 +
  999 + dsi->max_data_lanes = max_data_lanes;
  1000 + dsi->device = device;
  1001 + dsi->dsi_host.ops = &sec_mipi_dsim_host_ops;
  1002 + device->host = &dsi->dsi_host;
  1003 +
  1004 + dsi->base = (void *)dev_read_addr(device->dev);
  1005 + if ((fdt_addr_t)dsi->base == FDT_ADDR_T_NONE) {
  1006 + dev_err(device->dev, "dsi dt register address error\n");
  1007 + return -EINVAL;
  1008 + }
  1009 +
  1010 + dsi->timings = *timings;
  1011 +
  1012 + return 0;
  1013 +}
  1014 +
  1015 +static int sec_mipi_dsim_enable(struct udevice *dev)
  1016 +{
  1017 + return 0;
  1018 +}
  1019 +
  1020 +static int sec_mipi_dsim_disable(struct udevice *dev)
  1021 +{
  1022 + uint32_t intsrc;
  1023 + struct sec_mipi_dsim *dsim_host = dev_get_priv(dev);
  1024 +
  1025 + /* disable data transfer of dsim */
  1026 + sec_mipi_dsim_set_standby(dsim_host, false);
  1027 +
  1028 + /* disable esc clock & byte clock */
  1029 + sec_mipi_dsim_disable_clkctrl(dsim_host);
  1030 +
  1031 + /* disable dsim pll */
  1032 + sec_mipi_dsim_disable_pll(dsim_host);
  1033 +
  1034 + /* Clear all intsrc */
  1035 + intsrc = dsim_read(dsim_host, DSIM_INTSRC);
  1036 + dsim_write(dsim_host, intsrc, DSIM_INTSRC);
  1037 +
  1038 + return 0;
  1039 +}
  1040 +
  1041 +struct dsi_host_ops sec_mipi_dsim_ops = {
  1042 + .init = sec_mipi_dsim_init,
  1043 + .enable = sec_mipi_dsim_enable,
  1044 + .disable = sec_mipi_dsim_disable,
  1045 +};
  1046 +
  1047 +static int sec_mipi_dsim_probe(struct udevice *dev)
  1048 +{
  1049 + return 0;
  1050 +}
  1051 +
  1052 +static const struct udevice_id sec_mipi_dsim_ids[] = {
  1053 + { .compatible = "samsung,sec-mipi-dsi" },
  1054 + { }
  1055 +};
  1056 +
  1057 +U_BOOT_DRIVER(sec_mipi_dsim) = {
  1058 + .name = "sec_mipi_dsim",
  1059 + .id = UCLASS_DSI_HOST,
  1060 + .of_match = sec_mipi_dsim_ids,
  1061 + .probe = sec_mipi_dsim_probe,
  1062 + .remove = sec_mipi_dsim_disable,
  1063 + .ops = &sec_mipi_dsim_ops,
  1064 + .priv_auto_alloc_size = sizeof(struct sec_mipi_dsim),
  1065 +};
drivers/video/mxsfb.c
... ... @@ -20,12 +20,17 @@
20 20 #include <asm/arch/sys_proto.h>
21 21 #include <asm/mach-imx/dma.h>
22 22 #include <asm/io.h>
  23 +#include <reset.h>
  24 +#include <panel.h>
  25 +#include <video_bridge.h>
  26 +#include <video_link.h>
23 27  
24 28 #include "videomodes.h"
25 29 #include <linux/string.h>
26 30 #include <linux/list.h>
27 31 #include <linux/fb.h>
28 32 #include <mxsfb.h>
  33 +#include <dm/device-internal.h>
29 34  
30 35 #ifdef CONFIG_VIDEO_GIS
31 36 #include <gis.h>
... ... @@ -62,7 +67,7 @@
62 67 * le:89,ri:164,up:23,lo:10,hs:10,vs:10,sync:0,vmode:0
63 68 */
64 69  
65   -static void mxs_lcd_init(phys_addr_t reg_base, u32 fb_addr, struct ctfb_res_modes *mode, int bpp)
  70 +static void mxs_lcd_init(phys_addr_t reg_base, u32 fb_addr, struct ctfb_res_modes *mode, int bpp, bool bridge, bool enable_pol)
66 71 {
67 72 struct mxs_lcdif_regs *regs = (struct mxs_lcdif_regs *)(reg_base);
68 73 uint32_t word_len = 0, bus_width = 0;
69 74  
... ... @@ -104,15 +109,25 @@
104 109 writel(valid_data << LCDIF_CTRL1_BYTE_PACKING_FORMAT_OFFSET,
105 110 &regs->hw_lcdif_ctrl1);
106 111  
  112 + if (bridge)
  113 + writel(LCDIF_CTRL2_OUTSTANDING_REQS_REQ_16, &regs->hw_lcdif_ctrl2);
  114 +
107 115 mxsfb_system_setup();
108 116  
109 117 writel((mode->yres << LCDIF_TRANSFER_COUNT_V_COUNT_OFFSET) | mode->xres,
110 118 &regs->hw_lcdif_transfer_count);
111 119  
112   - writel(LCDIF_VDCTRL0_ENABLE_PRESENT | LCDIF_VDCTRL0_ENABLE_POL |
113   - LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT |
114   - LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
115   - mode->vsync_len, &regs->hw_lcdif_vdctrl0);
  120 + if (!enable_pol)
  121 + writel(LCDIF_VDCTRL0_ENABLE_PRESENT |
  122 + LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT |
  123 + LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
  124 + mode->vsync_len, &regs->hw_lcdif_vdctrl0);
  125 + else
  126 + writel(LCDIF_VDCTRL0_ENABLE_PRESENT | LCDIF_VDCTRL0_ENABLE_POL |
  127 + LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT |
  128 + LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
  129 + mode->vsync_len, &regs->hw_lcdif_vdctrl0);
  130 +
116 131 writel(mode->upper_margin + mode->lower_margin +
117 132 mode->vsync_len + mode->yres,
118 133 &regs->hw_lcdif_vdctrl1);
119 134  
... ... @@ -145,10 +160,10 @@
145 160 writel(LCDIF_CTRL_RUN, &regs->hw_lcdif_ctrl_set);
146 161 }
147 162  
148   -static int mxs_probe_common(phys_addr_t reg_base, struct ctfb_res_modes *mode, int bpp, u32 fb)
  163 +static int mxs_probe_common(phys_addr_t reg_base, struct ctfb_res_modes *mode, int bpp, u32 fb, bool bridge, bool enable_pol)
149 164 {
150 165 /* Start framebuffer */
151   - mxs_lcd_init(reg_base, fb, mode, bpp);
  166 + mxs_lcd_init(reg_base, fb, mode, bpp, bridge, enable_pol);
152 167  
153 168 #ifdef CONFIG_VIDEO_MXS_MODE_SYSTEM
154 169 /*
... ... @@ -324,7 +339,7 @@
324 339  
325 340 printf("%s\n", panel.modeIdent);
326 341  
327   - ret = mxs_probe_common(panel.isaBase, &mode, bpp, (u32)fb);
  342 + ret = mxs_probe_common(panel.isaBase, &mode, bpp, (u32)fb, false, true);
328 343 if (ret)
329 344 goto dealloc_fb;
330 345  
331 346  
... ... @@ -344,8 +359,74 @@
344 359  
345 360 struct mxsfb_priv {
346 361 fdt_addr_t reg_base;
  362 + struct udevice *disp_dev;
  363 +
  364 +#if IS_ENABLED(CONFIG_DM_RESET)
  365 + struct reset_ctl_bulk soft_resetn;
  366 + struct reset_ctl_bulk clk_enable;
  367 +#endif
347 368 };
348 369  
  370 +#if IS_ENABLED(CONFIG_DM_RESET)
  371 +static int lcdif_rstc_reset(struct reset_ctl_bulk *rstc, bool assert)
  372 +{
  373 + int ret;
  374 +
  375 + if (!rstc)
  376 + return 0;
  377 +
  378 + ret = assert ? reset_assert_bulk(rstc) :
  379 + reset_deassert_bulk(rstc);
  380 +
  381 + return ret;
  382 +}
  383 +
  384 +static int lcdif_of_parse_resets(struct udevice *dev)
  385 +{
  386 + int ret;
  387 + ofnode parent, child;
  388 + struct ofnode_phandle_args args;
  389 + struct reset_ctl_bulk rstc;
  390 + const char *compat;
  391 + uint32_t rstc_num = 0;
  392 +
  393 + struct mxsfb_priv *priv = dev_get_priv(dev);
  394 +
  395 + ret = dev_read_phandle_with_args(dev, "resets", "#reset-cells", 0,
  396 + 0, &args);
  397 + if (ret)
  398 + return ret;
  399 +
  400 + parent = args.node;
  401 + ofnode_for_each_subnode(child, parent) {
  402 + compat = ofnode_get_property(child, "compatible", NULL);
  403 + if (!compat)
  404 + continue;
  405 +
  406 + ret = reset_get_bulk_nodev(child, &rstc);
  407 + if (ret)
  408 + continue;
  409 +
  410 + if (!of_compat_cmp("lcdif,soft-resetn", compat, 0)) {
  411 + priv->soft_resetn = rstc;
  412 + rstc_num++;
  413 + } else if (!of_compat_cmp("lcdif,clk-enable", compat, 0)) {
  414 + priv->clk_enable = rstc;
  415 + rstc_num++;
  416 + }
  417 + else
  418 + dev_warn(dev, "invalid lcdif reset node: %s\n", compat);
  419 + }
  420 +
  421 + if (!rstc_num) {
  422 + dev_err(dev, "no invalid reset control exists\n");
  423 + return -EINVAL;
  424 + }
  425 +
  426 + return 0;
  427 +}
  428 +#endif
  429 +
349 430 static int mxs_of_get_timings(struct udevice *dev,
350 431 struct display_timing *timings,
351 432 u32 *bpp)
... ... @@ -353,6 +434,7 @@
353 434 int ret = 0;
354 435 u32 display_phandle;
355 436 ofnode display_node;
  437 + struct mxsfb_priv *priv = dev_get_priv(dev);
356 438  
357 439 ret = ofnode_read_u32(dev_ofnode(dev), "display", &display_phandle);
358 440 if (ret) {
... ... @@ -373,10 +455,19 @@
373 455 return -EINVAL;
374 456 }
375 457  
376   - ret = ofnode_decode_display_timing(display_node, 0, timings);
377   - if (ret) {
378   - dev_err(dev, "failed to get any display timings\n");
379   - return -EINVAL;
  458 + priv->disp_dev = video_link_get_next_device(dev);
  459 + if (priv->disp_dev) {
  460 + ret = video_link_get_display_timings(timings);
  461 + if (ret) {
  462 + dev_err(dev, "failed to get any video link display timings\n");
  463 + return -EINVAL;
  464 + }
  465 + } else {
  466 + ret = ofnode_decode_display_timing(display_node, 0, timings);
  467 + if (ret) {
  468 + dev_err(dev, "failed to get any display timings\n");
  469 + return -EINVAL;
  470 + }
380 471 }
381 472  
382 473 return ret;
383 474  
384 475  
... ... @@ -393,20 +484,72 @@
393 484 u32 bpp = 0;
394 485 u32 fb_start, fb_end;
395 486 int ret;
  487 + bool enable_pol = true, enable_bridge = false;
396 488  
397 489 debug("%s() plat: base 0x%lx, size 0x%x\n",
398 490 __func__, plat->base, plat->size);
399 491  
400   - ret = mxs_of_get_timings(dev, &timings, &bpp);
401   - if (ret)
402   - return ret;
403   -
404 492 priv->reg_base = dev_read_addr(dev);
405 493 if (priv->reg_base == FDT_ADDR_T_NONE) {
406 494 dev_err(dev, "lcdif base address is not found\n");
407 495 return -EINVAL;
408 496 }
409 497  
  498 + ret = mxs_of_get_timings(dev, &timings, &bpp);
  499 + if (ret)
  500 + return ret;
  501 +
  502 +#if IS_ENABLED(CONFIG_DM_RESET)
  503 + ret = lcdif_of_parse_resets(dev);
  504 + if (!ret) {
  505 + ret = lcdif_rstc_reset(&priv->soft_resetn, false);
  506 + if (ret) {
  507 + dev_err(dev, "deassert soft_resetn failed\n");
  508 + return ret;
  509 + }
  510 +
  511 + ret = lcdif_rstc_reset(&priv->clk_enable, true);
  512 + if (ret) {
  513 + dev_err(dev, "assert clk_enable failed\n");
  514 + return ret;
  515 + }
  516 + }
  517 +#endif
  518 +
  519 + if (priv->disp_dev) {
  520 +#if IS_ENABLED(CONFIG_VIDEO_BRIDGE)
  521 + if (device_get_uclass_id(priv->disp_dev) == UCLASS_VIDEO_BRIDGE) {
  522 + ret = video_bridge_attach(priv->disp_dev);
  523 + if (ret) {
  524 + dev_err(dev, "fail to attach bridge\n");
  525 + return ret;
  526 + }
  527 +
  528 + ret = video_bridge_set_backlight(priv->disp_dev, 80);
  529 + if (ret) {
  530 + dev_err(dev, "fail to set backlight\n");
  531 + return ret;
  532 + }
  533 +
  534 + enable_bridge = true;
  535 +
  536 + /* sec dsim needs enable ploarity at low, default we set to high */
  537 + if (dev_read_bool(dev, "enable_polarity_low"))
  538 + enable_pol = false;
  539 +
  540 + }
  541 +#endif
  542 +
  543 + if (device_get_uclass_id(priv->disp_dev) == UCLASS_PANEL) {
  544 + ret = panel_enable_backlight(priv->disp_dev);
  545 + if (ret) {
  546 + dev_err(dev, "panel %s enable backlight error %d\n",
  547 + priv->disp_dev->name, ret);
  548 + return ret;
  549 + }
  550 + }
  551 + }
  552 +
410 553 mode.xres = timings.hactive.typ;
411 554 mode.yres = timings.vactive.typ;
412 555 mode.left_margin = timings.hback_porch.typ;
... ... @@ -417,7 +560,7 @@
417 560 mode.vsync_len = timings.vsync_len.typ;
418 561 mode.pixclock = HZ2PS(timings.pixelclock.typ);
419 562  
420   - ret = mxs_probe_common(priv->reg_base, &mode, bpp, plat->base);
  563 + ret = mxs_probe_common(priv->reg_base, &mode, bpp, plat->base, enable_bridge, enable_pol);
421 564 if (ret)
422 565 return ret;
423 566  
424 567  
425 568  
... ... @@ -456,34 +599,10 @@
456 599 static int mxs_video_bind(struct udevice *dev)
457 600 {
458 601 struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
459   - struct display_timing timings;
460   - u32 bpp = 0;
461   - u32 bytes_pp = 0;
462   - int ret;
463 602  
464   - ret = mxs_of_get_timings(dev, &timings, &bpp);
465   - if (ret)
466   - return ret;
  603 + /* Max size supported by LCDIF, because in bind, we can't probe panel */
  604 + plat->size = 1920 * 1080 *4 * 2;
467 605  
468   - switch (bpp) {
469   - case 32:
470   - case 24:
471   - case 18:
472   - bytes_pp = 4;
473   - break;
474   - case 16:
475   - bytes_pp = 2;
476   - break;
477   - case 8:
478   - bytes_pp = 1;
479   - break;
480   - default:
481   - dev_err(dev, "invalid bpp specified (bpp = %i)\n", bpp);
482   - return -EINVAL;
483   - }
484   -
485   - plat->size = timings.hactive.typ * timings.vactive.typ * bytes_pp;
486   -
487 606 return 0;
488 607 }
489 608  
... ... @@ -492,6 +611,11 @@
492 611 struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
493 612 struct mxsfb_priv *priv = dev_get_priv(dev);
494 613  
  614 + debug("%s\n", __func__);
  615 +
  616 + if (priv->disp_dev)
  617 + device_remove(priv->disp_dev, DM_REMOVE_NORMAL);
  618 +
495 619 mxs_remove_common(priv->reg_base, plat->base);
496 620  
497 621 return 0;
... ... @@ -501,6 +625,8 @@
501 625 { .compatible = "fsl,imx23-lcdif" },
502 626 { .compatible = "fsl,imx28-lcdif" },
503 627 { .compatible = "fsl,imx7ulp-lcdif" },
  628 + { .compatible = "fsl,imx8mm-lcdif" },
  629 + { .compatible = "fsl,imx8mn-lcdif" },
504 630 { /* sentinel */ }
505 631 };
506 632  
drivers/video/raydium-rm67191.c
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +/*
  3 + * Copyright 2019 NXP
  4 + *
  5 + */
  6 +
  7 +#include <common.h>
  8 +#include <dm.h>
  9 +#include <mipi_dsi.h>
  10 +#include <panel.h>
  11 +#include <asm/gpio.h>
  12 +#include <linux/err.h>
  13 +
  14 +#define CMD_TABLE_LEN 2
  15 +typedef u8 cmd_set_table[CMD_TABLE_LEN];
  16 +
  17 +/* Write Manufacture Command Set Control */
  18 +#define WRMAUCCTR 0xFE
  19 +
  20 +struct rm67191_panel_priv {
  21 + struct gpio_desc reset;
  22 + unsigned int lanes;
  23 + enum mipi_dsi_pixel_format format;
  24 + unsigned long mode_flags;
  25 +};
  26 +
  27 +/* Manufacturer Command Set pages (CMD2) */
  28 +static const cmd_set_table manufacturer_cmd_set[] = {
  29 + {0xFE, 0x0B},
  30 + {0x28, 0x40},
  31 + {0x29, 0x4F},
  32 + {0xFE, 0x0E},
  33 + {0x4B, 0x00},
  34 + {0x4C, 0x0F},
  35 + {0x4D, 0x20},
  36 + {0x4E, 0x40},
  37 + {0x4F, 0x60},
  38 + {0x50, 0xA0},
  39 + {0x51, 0xC0},
  40 + {0x52, 0xE0},
  41 + {0x53, 0xFF},
  42 + {0xFE, 0x0D},
  43 + {0x18, 0x08},
  44 + {0x42, 0x00},
  45 + {0x08, 0x41},
  46 + {0x46, 0x02},
  47 + {0x72, 0x09},
  48 + {0xFE, 0x0A},
  49 + {0x24, 0x17},
  50 + {0x04, 0x07},
  51 + {0x1A, 0x0C},
  52 + {0x0F, 0x44},
  53 + {0xFE, 0x04},
  54 + {0x00, 0x0C},
  55 + {0x05, 0x08},
  56 + {0x06, 0x08},
  57 + {0x08, 0x08},
  58 + {0x09, 0x08},
  59 + {0x0A, 0xE6},
  60 + {0x0B, 0x8C},
  61 + {0x1A, 0x12},
  62 + {0x1E, 0xE0},
  63 + {0x29, 0x93},
  64 + {0x2A, 0x93},
  65 + {0x2F, 0x02},
  66 + {0x31, 0x02},
  67 + {0x33, 0x05},
  68 + {0x37, 0x2D},
  69 + {0x38, 0x2D},
  70 + {0x3A, 0x1E},
  71 + {0x3B, 0x1E},
  72 + {0x3D, 0x27},
  73 + {0x3F, 0x80},
  74 + {0x40, 0x40},
  75 + {0x41, 0xE0},
  76 + {0x4F, 0x2F},
  77 + {0x50, 0x1E},
  78 + {0xFE, 0x06},
  79 + {0x00, 0xCC},
  80 + {0x05, 0x05},
  81 + {0x07, 0xA2},
  82 + {0x08, 0xCC},
  83 + {0x0D, 0x03},
  84 + {0x0F, 0xA2},
  85 + {0x32, 0xCC},
  86 + {0x37, 0x05},
  87 + {0x39, 0x83},
  88 + {0x3A, 0xCC},
  89 + {0x41, 0x04},
  90 + {0x43, 0x83},
  91 + {0x44, 0xCC},
  92 + {0x49, 0x05},
  93 + {0x4B, 0xA2},
  94 + {0x4C, 0xCC},
  95 + {0x51, 0x03},
  96 + {0x53, 0xA2},
  97 + {0x75, 0xCC},
  98 + {0x7A, 0x03},
  99 + {0x7C, 0x83},
  100 + {0x7D, 0xCC},
  101 + {0x82, 0x02},
  102 + {0x84, 0x83},
  103 + {0x85, 0xEC},
  104 + {0x86, 0x0F},
  105 + {0x87, 0xFF},
  106 + {0x88, 0x00},
  107 + {0x8A, 0x02},
  108 + {0x8C, 0xA2},
  109 + {0x8D, 0xEA},
  110 + {0x8E, 0x01},
  111 + {0x8F, 0xE8},
  112 + {0xFE, 0x06},
  113 + {0x90, 0x0A},
  114 + {0x92, 0x06},
  115 + {0x93, 0xA0},
  116 + {0x94, 0xA8},
  117 + {0x95, 0xEC},
  118 + {0x96, 0x0F},
  119 + {0x97, 0xFF},
  120 + {0x98, 0x00},
  121 + {0x9A, 0x02},
  122 + {0x9C, 0xA2},
  123 + {0xAC, 0x04},
  124 + {0xFE, 0x06},
  125 + {0xB1, 0x12},
  126 + {0xB2, 0x17},
  127 + {0xB3, 0x17},
  128 + {0xB4, 0x17},
  129 + {0xB5, 0x17},
  130 + {0xB6, 0x11},
  131 + {0xB7, 0x08},
  132 + {0xB8, 0x09},
  133 + {0xB9, 0x06},
  134 + {0xBA, 0x07},
  135 + {0xBB, 0x17},
  136 + {0xBC, 0x17},
  137 + {0xBD, 0x17},
  138 + {0xBE, 0x17},
  139 + {0xBF, 0x17},
  140 + {0xC0, 0x17},
  141 + {0xC1, 0x17},
  142 + {0xC2, 0x17},
  143 + {0xC3, 0x17},
  144 + {0xC4, 0x0F},
  145 + {0xC5, 0x0E},
  146 + {0xC6, 0x00},
  147 + {0xC7, 0x01},
  148 + {0xC8, 0x10},
  149 + {0xFE, 0x06},
  150 + {0x95, 0xEC},
  151 + {0x8D, 0xEE},
  152 + {0x44, 0xEC},
  153 + {0x4C, 0xEC},
  154 + {0x32, 0xEC},
  155 + {0x3A, 0xEC},
  156 + {0x7D, 0xEC},
  157 + {0x75, 0xEC},
  158 + {0x00, 0xEC},
  159 + {0x08, 0xEC},
  160 + {0x85, 0xEC},
  161 + {0xA6, 0x21},
  162 + {0xA7, 0x05},
  163 + {0xA9, 0x06},
  164 + {0x82, 0x06},
  165 + {0x41, 0x06},
  166 + {0x7A, 0x07},
  167 + {0x37, 0x07},
  168 + {0x05, 0x06},
  169 + {0x49, 0x06},
  170 + {0x0D, 0x04},
  171 + {0x51, 0x04},
  172 +};
  173 +
  174 +static const struct display_timing default_timing = {
  175 + .pixelclock.typ = 132000000,
  176 + .hactive.typ = 1080,
  177 + .hfront_porch.typ = 20,
  178 + .hback_porch.typ = 34,
  179 + .hsync_len.typ = 2,
  180 + .vactive.typ = 1920,
  181 + .vfront_porch.typ = 10,
  182 + .vback_porch.typ = 4,
  183 + .vsync_len.typ = 2,
  184 + .flags = DISPLAY_FLAGS_HSYNC_LOW |
  185 + DISPLAY_FLAGS_VSYNC_LOW |
  186 + DISPLAY_FLAGS_DE_LOW |
  187 + DISPLAY_FLAGS_PIXDATA_NEGEDGE,
  188 +};
  189 +
  190 +
  191 +static u8 color_format_from_dsi_format(enum mipi_dsi_pixel_format format)
  192 +{
  193 + switch (format) {
  194 + case MIPI_DSI_FMT_RGB565:
  195 + return 0x55;
  196 + case MIPI_DSI_FMT_RGB666:
  197 + case MIPI_DSI_FMT_RGB666_PACKED:
  198 + return 0x66;
  199 + case MIPI_DSI_FMT_RGB888:
  200 + return 0x77;
  201 + default:
  202 + return 0x77; /* for backward compatibility */
  203 + }
  204 +};
  205 +
  206 +static int rad_panel_push_cmd_list(struct mipi_dsi_device *device)
  207 +{
  208 + size_t i;
  209 + const u8 *cmd;
  210 + size_t count = sizeof(manufacturer_cmd_set) / CMD_TABLE_LEN;
  211 + int ret = 0;
  212 +
  213 + for (i = 0; i < count ; i++) {
  214 + cmd = manufacturer_cmd_set[i];
  215 + ret = mipi_dsi_generic_write(device, cmd, CMD_TABLE_LEN);
  216 + if (ret < 0)
  217 + return ret;
  218 + }
  219 +
  220 + return ret;
  221 +};
  222 +
  223 +static int rm67191_enable(struct udevice *dev)
  224 +{
  225 + struct rm67191_panel_priv *priv = dev_get_priv(dev);
  226 + struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev);
  227 + struct mipi_dsi_device *dsi = plat->device;
  228 + u8 color_format = color_format_from_dsi_format(priv->format);
  229 + u16 brightness;
  230 + int ret;
  231 +
  232 + dsi->mode_flags |= MIPI_DSI_MODE_LPM;
  233 +
  234 + ret = rad_panel_push_cmd_list(dsi);
  235 + if (ret < 0) {
  236 + printf("Failed to send MCS (%d)\n", ret);
  237 + return -EIO;
  238 + }
  239 +
  240 + /* Select User Command Set table (CMD1) */
  241 + ret = mipi_dsi_generic_write(dsi, (u8[]){ WRMAUCCTR, 0x00 }, 2);
  242 + if (ret < 0)
  243 + return -EIO;
  244 +
  245 + /* Software reset */
  246 + ret = mipi_dsi_dcs_soft_reset(dsi);
  247 + if (ret < 0) {
  248 + printf("Failed to do Software Reset (%d)\n", ret);
  249 + return -EIO;
  250 + }
  251 +
  252 + /* Wait 80ms for panel out of reset */
  253 + mdelay(80);
  254 +
  255 + /* Set DSI mode */
  256 + ret = mipi_dsi_generic_write(dsi, (u8[]){ 0xC2, 0x0B }, 2);
  257 + if (ret < 0) {
  258 + printf("Failed to set DSI mode (%d)\n", ret);
  259 + return -EIO;
  260 + }
  261 +
  262 + /* Set tear ON */
  263 + ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
  264 + if (ret < 0) {
  265 + printf("Failed to set tear ON (%d)\n", ret);
  266 + return -EIO;
  267 + }
  268 +
  269 + /* Set tear scanline */
  270 + ret = mipi_dsi_dcs_set_tear_scanline(dsi, 0x380);
  271 + if (ret < 0) {
  272 + printf("Failed to set tear scanline (%d)\n", ret);
  273 + return -EIO;
  274 + }
  275 +
  276 + /* Set pixel format */
  277 + ret = mipi_dsi_dcs_set_pixel_format(dsi, color_format);
  278 + if (ret < 0) {
  279 + printf("Failed to set pixel format (%d)\n", ret);
  280 + return -EIO;
  281 + }
  282 +
  283 +
  284 + /* Set display brightness */
  285 + brightness = 255; /* Max brightness */
  286 + ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, &brightness, 2);
  287 + if (ret < 0) {
  288 + printf("Failed to set display brightness (%d)\n",
  289 + ret);
  290 + return -EIO;
  291 + }
  292 +
  293 + /* Exit sleep mode */
  294 + ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
  295 + if (ret < 0) {
  296 + printf("Failed to exit sleep mode (%d)\n", ret);
  297 + return -EIO;
  298 + }
  299 +
  300 + mdelay(5);
  301 +
  302 + ret = mipi_dsi_dcs_set_display_on(dsi);
  303 + if (ret < 0) {
  304 + printf("Failed to set display ON (%d)\n", ret);
  305 + return -EIO;
  306 + }
  307 +
  308 + return 0;
  309 +}
  310 +
  311 +static int rm67191_panel_enable_backlight(struct udevice *dev)
  312 +{
  313 + struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev);
  314 + struct mipi_dsi_device *device = plat->device;
  315 + int ret;
  316 +
  317 + ret = mipi_dsi_attach(device);
  318 + if (ret < 0)
  319 + return ret;
  320 +
  321 + return rm67191_enable(dev);
  322 +}
  323 +
  324 +static int rm67191_panel_get_display_timing(struct udevice *dev,
  325 + struct display_timing *timings)
  326 +{
  327 + struct mipi_dsi_panel_plat *plat = dev_get_platdata(dev);
  328 + struct mipi_dsi_device *device = plat->device;
  329 + struct rm67191_panel_priv *priv = dev_get_priv(dev);
  330 +
  331 + memcpy(timings, &default_timing, sizeof(*timings));
  332 +
  333 + /* fill characteristics of DSI data link */
  334 + if (device) {
  335 + device->lanes = priv->lanes;
  336 + device->format = priv->format;
  337 + device->mode_flags = priv->mode_flags;
  338 + }
  339 +
  340 + return 0;
  341 +}
  342 +
  343 +static int rm67191_panel_probe(struct udevice *dev)
  344 +{
  345 + struct rm67191_panel_priv *priv = dev_get_priv(dev);
  346 + int ret;
  347 + u32 video_mode;
  348 +
  349 + priv->format = MIPI_DSI_FMT_RGB888;
  350 + priv->mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO;
  351 +
  352 + ret = dev_read_u32(dev, "video-mode", &video_mode);
  353 + if (!ret) {
  354 + switch (video_mode) {
  355 + case 0:
  356 + /* burst mode */
  357 + priv->mode_flags |= MIPI_DSI_MODE_VIDEO_BURST;
  358 + break;
  359 + case 1:
  360 + /* non-burst mode with sync event */
  361 + break;
  362 + case 2:
  363 + /* non-burst mode with sync pulse */
  364 + priv->mode_flags |= MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
  365 + break;
  366 + default:
  367 + dev_warn(dev, "invalid video mode %d\n", video_mode);
  368 + break;
  369 + }
  370 + }
  371 +
  372 + ret = dev_read_u32(dev, "dsi-lanes", &priv->lanes);
  373 + if (ret) {
  374 + printf("Failed to get dsi-lanes property (%d)\n", ret);
  375 + return ret;
  376 + }
  377 +
  378 + ret = gpio_request_by_name(dev, "reset-gpio", 0, &priv->reset,
  379 + GPIOD_IS_OUT);
  380 + if (ret) {
  381 + printf("Warning: cannot get reset GPIO\n");
  382 + if (ret != -ENOENT)
  383 + return ret;
  384 + }
  385 +
  386 + /* reset panel */
  387 + ret = dm_gpio_set_value(&priv->reset, true);
  388 + if (ret)
  389 + printf("reset gpio fails to set true\n");
  390 + mdelay(100);
  391 + ret = dm_gpio_set_value(&priv->reset, false);
  392 + if (ret)
  393 + printf("reset gpio fails to set true\n");
  394 + mdelay(100);
  395 +
  396 + return 0;
  397 +}
  398 +
  399 +static int rm67191_panel_disable(struct udevice *dev)
  400 +{
  401 + struct rm67191_panel_priv *priv = dev_get_priv(dev);
  402 +
  403 + dm_gpio_set_value(&priv->reset, true);
  404 +
  405 + return 0;
  406 +}
  407 +
  408 +static const struct panel_ops rm67191_panel_ops = {
  409 + .enable_backlight = rm67191_panel_enable_backlight,
  410 + .get_display_timing = rm67191_panel_get_display_timing,
  411 +};
  412 +
  413 +static const struct udevice_id rm67191_panel_ids[] = {
  414 + { .compatible = "raydium,rm67191" },
  415 + { }
  416 +};
  417 +
  418 +U_BOOT_DRIVER(rm67191_panel) = {
  419 + .name = "rm67191_panel",
  420 + .id = UCLASS_PANEL,
  421 + .of_match = rm67191_panel_ids,
  422 + .ops = &rm67191_panel_ops,
  423 + .probe = rm67191_panel_probe,
  424 + .remove = rm67191_panel_disable,
  425 + .platdata_auto_alloc_size = sizeof(struct mipi_dsi_panel_plat),
  426 + .priv_auto_alloc_size = sizeof(struct rm67191_panel_priv),
  427 +};