Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Ilitek ILI9341 TFT LCD drm_panel driver.
0004  *
0005  * This panel can be configured to support:
0006  * - 16-bit parallel RGB interface
0007  * - 18-bit parallel RGB interface
0008  * - 4-line serial spi interface
0009  *
0010  * Copyright (C) 2021 Dillon Min <dillon.minfei@gmail.com>
0011  *
0012  * For dbi+dpi part:
0013  * Derived from drivers/drm/gpu/panel/panel-ilitek-ili9322.c
0014  * the reuse of DBI abstraction part referred from Linus's patch
0015  * "drm/panel: s6e63m0: Switch to DBI abstraction for SPI"
0016  *
0017  * For only-dbi part, copy from David's code (drm/tiny/ili9341.c)
0018  * Copyright 2018 David Lechner <david@lechnology.com>
0019  */
0020 
0021 #include <linux/bitops.h>
0022 #include <linux/delay.h>
0023 #include <linux/gpio/consumer.h>
0024 #include <linux/module.h>
0025 #include <linux/of_device.h>
0026 #include <linux/regulator/consumer.h>
0027 #include <linux/spi/spi.h>
0028 
0029 #include <video/mipi_display.h>
0030 
0031 #include <drm/drm_atomic_helper.h>
0032 #include <drm/drm_drv.h>
0033 #include <drm/drm_fb_helper.h>
0034 #include <drm/drm_gem_atomic_helper.h>
0035 #include <drm/drm_gem_cma_helper.h>
0036 #include <drm/drm_gem_framebuffer_helper.h>
0037 #include <drm/drm_mipi_dbi.h>
0038 #include <drm/drm_modes.h>
0039 #include <drm/drm_panel.h>
0040 #include <drm/drm_print.h>
0041 
0042 #define ILI9341_RGB_INTERFACE  0xb0   /* RGB Interface Signal Control */
0043 #define ILI9341_FRC            0xb1   /* Frame Rate Control register */
0044 #define ILI9341_DFC            0xb6   /* Display Function Control register */
0045 #define ILI9341_POWER1         0xc0   /* Power Control 1 register */
0046 #define ILI9341_POWER2         0xc1   /* Power Control 2 register */
0047 #define ILI9341_VCOM1          0xc5   /* VCOM Control 1 register */
0048 #define ILI9341_VCOM2          0xc7   /* VCOM Control 2 register */
0049 #define ILI9341_POWERA         0xcb   /* Power control A register */
0050 #define ILI9341_POWERB         0xcf   /* Power control B register */
0051 #define ILI9341_PGAMMA         0xe0   /* Positive Gamma Correction register */
0052 #define ILI9341_NGAMMA         0xe1   /* Negative Gamma Correction register */
0053 #define ILI9341_DTCA           0xe8   /* Driver timing control A */
0054 #define ILI9341_DTCB           0xea   /* Driver timing control B */
0055 #define ILI9341_POWER_SEQ      0xed   /* Power on sequence register */
0056 #define ILI9341_3GAMMA_EN      0xf2   /* 3 Gamma enable register */
0057 #define ILI9341_INTERFACE      0xf6   /* Interface control register */
0058 #define ILI9341_PRC            0xf7   /* Pump ratio control register */
0059 #define ILI9341_ETMOD          0xb7   /* Entry mode set */
0060 
0061 #define ILI9341_MADCTL_BGR  BIT(3)
0062 #define ILI9341_MADCTL_MV   BIT(5)
0063 #define ILI9341_MADCTL_MX   BIT(6)
0064 #define ILI9341_MADCTL_MY   BIT(7)
0065 
0066 #define ILI9341_POWER_B_LEN 3
0067 #define ILI9341_POWER_SEQ_LEN   4
0068 #define ILI9341_DTCA_LEN    3
0069 #define ILI9341_DTCB_LEN    2
0070 #define ILI9341_POWER_A_LEN 5
0071 #define ILI9341_DFC_1_LEN   2
0072 #define ILI9341_FRC_LEN     2
0073 #define ILI9341_VCOM_1_LEN  2
0074 #define ILI9341_DFC_2_LEN   4
0075 #define ILI9341_COLUMN_ADDR_LEN 4
0076 #define ILI9341_PAGE_ADDR_LEN   4
0077 #define ILI9341_INTERFACE_LEN   3
0078 #define ILI9341_PGAMMA_LEN  15
0079 #define ILI9341_NGAMMA_LEN  15
0080 #define ILI9341_CA_LEN      3
0081 
0082 #define ILI9341_PIXEL_DPI_16_BITS   (BIT(6) | BIT(4))
0083 #define ILI9341_PIXEL_DPI_18_BITS   (BIT(6) | BIT(5))
0084 #define ILI9341_GAMMA_CURVE_1       BIT(0)
0085 #define ILI9341_IF_WE_MODE      BIT(0)
0086 #define ILI9341_IF_BIG_ENDIAN       0x00
0087 #define ILI9341_IF_DM_RGB       BIT(2)
0088 #define ILI9341_IF_DM_INTERNAL      0x00
0089 #define ILI9341_IF_DM_VSYNC     BIT(3)
0090 #define ILI9341_IF_RM_RGB       BIT(1)
0091 #define ILI9341_IF_RIM_RGB      0x00
0092 
0093 #define ILI9341_COLUMN_ADDR     0x00ef
0094 #define ILI9341_PAGE_ADDR       0x013f
0095 
0096 #define ILI9341_RGB_EPL         BIT(0)
0097 #define ILI9341_RGB_DPL         BIT(1)
0098 #define ILI9341_RGB_HSPL        BIT(2)
0099 #define ILI9341_RGB_VSPL        BIT(3)
0100 #define ILI9341_RGB_DE_MODE     BIT(6)
0101 #define ILI9341_RGB_DISP_PATH_MEM   BIT(7)
0102 
0103 #define ILI9341_DBI_VCOMH_4P6V      0x23
0104 #define ILI9341_DBI_PWR_2_DEFAULT   0x10
0105 #define ILI9341_DBI_PRC_NORMAL      0x20
0106 #define ILI9341_DBI_VCOM_1_VMH_4P25V    0x3e
0107 #define ILI9341_DBI_VCOM_1_VML_1P5V 0x28
0108 #define ILI9341_DBI_VCOM_2_DEC_58   0x86
0109 #define ILI9341_DBI_FRC_DIVA        0x00
0110 #define ILI9341_DBI_FRC_RTNA        0x1b
0111 #define ILI9341_DBI_EMS_GAS     BIT(0)
0112 #define ILI9341_DBI_EMS_DTS     BIT(1)
0113 #define ILI9341_DBI_EMS_GON     BIT(2)
0114 
0115 /* struct ili9341_config - the system specific ILI9341 configuration */
0116 struct ili9341_config {
0117     u32 max_spi_speed;
0118     /* mode: the drm display mode */
0119     const struct drm_display_mode mode;
0120     /* ca: TODO: need comments for this register */
0121     u8 ca[ILI9341_CA_LEN];
0122     /* power_b: TODO: need comments for this register */
0123     u8 power_b[ILI9341_POWER_B_LEN];
0124     /* power_seq: TODO: need comments for this register */
0125     u8 power_seq[ILI9341_POWER_SEQ_LEN];
0126     /* dtca: TODO: need comments for this register */
0127     u8 dtca[ILI9341_DTCA_LEN];
0128     /* dtcb: TODO: need comments for this register */
0129     u8 dtcb[ILI9341_DTCB_LEN];
0130     /* power_a: TODO: need comments for this register */
0131     u8 power_a[ILI9341_POWER_A_LEN];
0132     /* frc: Frame Rate Control (In Normal Mode/Full Colors) (B1h) */
0133     u8 frc[ILI9341_FRC_LEN];
0134     /* prc: TODO: need comments for this register */
0135     u8 prc;
0136     /* dfc_1: B6h DISCTRL (Display Function Control) */
0137     u8 dfc_1[ILI9341_DFC_1_LEN];
0138     /* power_1: Power Control 1 (C0h) */
0139     u8 power_1;
0140     /* power_2: Power Control 2 (C1h) */
0141     u8 power_2;
0142     /* vcom_1: VCOM Control 1(C5h) */
0143     u8 vcom_1[ILI9341_VCOM_1_LEN];
0144     /* vcom_2: VCOM Control 2(C7h) */
0145     u8 vcom_2;
0146     /* address_mode: Memory Access Control (36h) */
0147     u8 address_mode;
0148     /* g3amma_en: TODO: need comments for this register */
0149     u8 g3amma_en;
0150     /* rgb_interface: RGB Interface Signal Control (B0h) */
0151     u8 rgb_interface;
0152     /* dfc_2: refer to dfc_1 */
0153     u8 dfc_2[ILI9341_DFC_2_LEN];
0154     /* column_addr: Column Address Set (2Ah) */
0155     u8 column_addr[ILI9341_COLUMN_ADDR_LEN];
0156     /* page_addr: Page Address Set (2Bh) */
0157     u8 page_addr[ILI9341_PAGE_ADDR_LEN];
0158     /* interface: Interface Control (F6h) */
0159     u8 interface[ILI9341_INTERFACE_LEN];
0160     /*
0161      * pixel_format: This command sets the pixel format for the RGB
0162      * image data used by
0163      */
0164     u8 pixel_format;
0165     /*
0166      * gamma_curve: This command is used to select the desired Gamma
0167      * curve for the
0168      */
0169     u8 gamma_curve;
0170     /* pgamma: Positive Gamma Correction (E0h) */
0171     u8 pgamma[ILI9341_PGAMMA_LEN];
0172     /* ngamma: Negative Gamma Correction (E1h) */
0173     u8 ngamma[ILI9341_NGAMMA_LEN];
0174 };
0175 
0176 struct ili9341 {
0177     struct device *dev;
0178     const struct ili9341_config *conf;
0179     struct drm_panel panel;
0180     struct gpio_desc *reset_gpio;
0181     struct gpio_desc *dc_gpio;
0182     struct mipi_dbi *dbi;
0183     u32 max_spi_speed;
0184     struct regulator_bulk_data supplies[3];
0185 };
0186 
0187 /*
0188  * The Stm32f429-disco board has a panel ili9341 connected to ltdc controller
0189  */
0190 static const struct ili9341_config ili9341_stm32f429_disco_data = {
0191     .max_spi_speed = 10000000,
0192     .mode = {
0193         .clock = 6100,
0194         .hdisplay = 240,
0195         .hsync_start = 240 + 10,/* hfp 10 */
0196         .hsync_end = 240 + 10 + 10,/* hsync 10 */
0197         .htotal = 240 + 10 + 10 + 20,/* hbp 20 */
0198         .vdisplay = 320,
0199         .vsync_start = 320 + 4,/* vfp 4 */
0200         .vsync_end = 320 + 4 + 2,/* vsync 2 */
0201         .vtotal = 320 + 4 + 2 + 2,/* vbp 2 */
0202         .flags = 0,
0203         .width_mm = 65,
0204         .height_mm = 50,
0205         .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
0206     },
0207     .ca = {0xc3, 0x08, 0x50},
0208     .power_b = {0x00, 0xc1, 0x30},
0209     .power_seq = {0x64, 0x03, 0x12, 0x81},
0210     .dtca = {0x85, 0x00, 0x78},
0211     .power_a = {0x39, 0x2c, 0x00, 0x34, 0x02},
0212     .prc = 0x20,
0213     .dtcb = {0x00, 0x00},
0214     /* 0x00 fosc, 0x1b 70hz */
0215     .frc = {0x00, 0x1b},
0216     /*
0217      * 0x0a Interval scan, AGND AGND AGND AGND
0218      * 0xa2 Normally white, G1 -> G320, S720 -> S1,
0219      *  Scan Cycle 5 frames,85ms
0220      */
0221     .dfc_1 = {0x0a, 0xa2},
0222     /* 0x10 3.65v */
0223     .power_1 = 0x10,
0224     /* 0x10 AVDD=vci*2, VGH=vci*7, VGL=-vci*4 */
0225     .power_2 = 0x10,
0226     /* 0x45 VCOMH 4.425v, 0x15 VCOML -1.975*/
0227     .vcom_1 = {0x45, 0x15},
0228     /* 0x90 offset voltage, VMH-48, VML-48 */
0229     .vcom_2 = 0x90,
0230     /*
0231      * 0xc8 Row Address Order, Column Address Order
0232      * BGR 1
0233      */
0234     .address_mode = 0xc8,
0235     .g3amma_en = 0x00,
0236     /*
0237      * 0xc2
0238      * Display Data Path: Memory
0239      * RGB: DE mode
0240      * DOTCLK polarity set (data fetched at the falling time)
0241      */
0242     .rgb_interface = ILI9341_RGB_DISP_PATH_MEM |
0243             ILI9341_RGB_DE_MODE |
0244             ILI9341_RGB_DPL,
0245     /*
0246      * 0x0a
0247      * Gate outputs in non-display area: Interval scan
0248      * Determine source/VCOM output in a non-display area in the partial
0249      * display mode: AGND AGND AGND AGND
0250      *
0251      * 0xa7
0252      * Scan Cycle: 15 frames
0253      * fFLM = 60Hz: 255ms
0254      * Liquid crystal type: Normally white
0255      * Gate Output Scan Direction: G1 -> G320
0256      * Source Output Scan Direction: S720 -> S1
0257      *
0258      * 0x27
0259      * LCD Driver Line: 320 lines
0260      *
0261      * 0x04
0262      * PCDIV: 4
0263      */
0264     .dfc_2 = {0x0a, 0xa7, 0x27, 0x04},
0265     /* column address: 240 */
0266     .column_addr = {0x00, 0x00, (ILI9341_COLUMN_ADDR >> 4) & 0xff,
0267                 ILI9341_COLUMN_ADDR & 0xff},
0268     /* page address: 320 */
0269     .page_addr = {0x00, 0x00, (ILI9341_PAGE_ADDR >> 4) & 0xff,
0270                 ILI9341_PAGE_ADDR & 0xff},
0271     /*
0272      * Memory write control: When the transfer number of data exceeds
0273      * (EC-SC+1)*(EP-SP+1), the column and page number will be
0274      * reset, and the exceeding data will be written into the following
0275      * column and page.
0276      * Display Operation Mode: RGB Interface Mode
0277      * Interface for RAM Access: RGB interface
0278      * 16- bit RGB interface (1 transfer/pixel)
0279      */
0280     .interface = {ILI9341_IF_WE_MODE, 0x00,
0281             ILI9341_IF_DM_RGB | ILI9341_IF_RM_RGB},
0282     /* DPI: 16 bits / pixel */
0283     .pixel_format = ILI9341_PIXEL_DPI_16_BITS,
0284     /* Curve Selected: Gamma curve 1 (G2.2) */
0285     .gamma_curve = ILI9341_GAMMA_CURVE_1,
0286     .pgamma = {0x0f, 0x29, 0x24, 0x0c, 0x0e,
0287             0x09, 0x4e, 0x78, 0x3c, 0x09,
0288             0x13, 0x05, 0x17, 0x11, 0x00},
0289     .ngamma = {0x00, 0x16, 0x1b, 0x04, 0x11,
0290             0x07, 0x31, 0x33, 0x42, 0x05,
0291             0x0c, 0x0a, 0x28, 0x2f, 0x0f},
0292 };
0293 
0294 static inline struct ili9341 *panel_to_ili9341(struct drm_panel *panel)
0295 {
0296     return container_of(panel, struct ili9341, panel);
0297 }
0298 
0299 static void ili9341_dpi_init(struct ili9341 *ili)
0300 {
0301     struct device *dev = (&ili->panel)->dev;
0302     struct mipi_dbi *dbi = ili->dbi;
0303     struct ili9341_config *cfg = (struct ili9341_config *)ili->conf;
0304 
0305     /* Power Control */
0306     mipi_dbi_command_stackbuf(dbi, 0xca, cfg->ca, ILI9341_CA_LEN);
0307     mipi_dbi_command_stackbuf(dbi, ILI9341_POWERB, cfg->power_b,
0308                   ILI9341_POWER_B_LEN);
0309     mipi_dbi_command_stackbuf(dbi, ILI9341_POWER_SEQ, cfg->power_seq,
0310                   ILI9341_POWER_SEQ_LEN);
0311     mipi_dbi_command_stackbuf(dbi, ILI9341_DTCA, cfg->dtca,
0312                   ILI9341_DTCA_LEN);
0313     mipi_dbi_command_stackbuf(dbi, ILI9341_POWERA, cfg->power_a,
0314                   ILI9341_POWER_A_LEN);
0315     mipi_dbi_command(ili->dbi, ILI9341_PRC, cfg->prc);
0316     mipi_dbi_command_stackbuf(dbi, ILI9341_DTCB, cfg->dtcb,
0317                   ILI9341_DTCB_LEN);
0318     mipi_dbi_command_stackbuf(dbi, ILI9341_FRC, cfg->frc, ILI9341_FRC_LEN);
0319     mipi_dbi_command_stackbuf(dbi, ILI9341_DFC, cfg->dfc_1,
0320                   ILI9341_DFC_1_LEN);
0321     mipi_dbi_command(dbi, ILI9341_POWER1, cfg->power_1);
0322     mipi_dbi_command(dbi, ILI9341_POWER2, cfg->power_2);
0323 
0324     /* VCOM */
0325     mipi_dbi_command_stackbuf(dbi, ILI9341_VCOM1, cfg->vcom_1,
0326                   ILI9341_VCOM_1_LEN);
0327     mipi_dbi_command(dbi, ILI9341_VCOM2, cfg->vcom_2);
0328     mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, cfg->address_mode);
0329 
0330     /* Gamma */
0331     mipi_dbi_command(dbi, ILI9341_3GAMMA_EN, cfg->g3amma_en);
0332     mipi_dbi_command(dbi, ILI9341_RGB_INTERFACE, cfg->rgb_interface);
0333     mipi_dbi_command_stackbuf(dbi, ILI9341_DFC, cfg->dfc_2,
0334                   ILI9341_DFC_2_LEN);
0335 
0336     /* Colomn address set */
0337     mipi_dbi_command_stackbuf(dbi, MIPI_DCS_SET_COLUMN_ADDRESS,
0338                   cfg->column_addr, ILI9341_COLUMN_ADDR_LEN);
0339 
0340     /* Page address set */
0341     mipi_dbi_command_stackbuf(dbi, MIPI_DCS_SET_PAGE_ADDRESS,
0342                   cfg->page_addr, ILI9341_PAGE_ADDR_LEN);
0343     mipi_dbi_command_stackbuf(dbi, ILI9341_INTERFACE, cfg->interface,
0344                   ILI9341_INTERFACE_LEN);
0345 
0346     /* Format */
0347     mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, cfg->pixel_format);
0348     mipi_dbi_command(dbi, MIPI_DCS_WRITE_MEMORY_START);
0349     msleep(200);
0350     mipi_dbi_command(dbi, MIPI_DCS_SET_GAMMA_CURVE, cfg->gamma_curve);
0351     mipi_dbi_command_stackbuf(dbi, ILI9341_PGAMMA, cfg->pgamma,
0352                   ILI9341_PGAMMA_LEN);
0353     mipi_dbi_command_stackbuf(dbi, ILI9341_NGAMMA, cfg->ngamma,
0354                   ILI9341_NGAMMA_LEN);
0355     mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
0356     msleep(200);
0357     mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
0358     mipi_dbi_command(dbi, MIPI_DCS_WRITE_MEMORY_START);
0359 
0360     dev_info(dev, "Initialized display rgb interface\n");
0361 }
0362 
0363 static int ili9341_dpi_power_on(struct ili9341 *ili)
0364 {
0365     struct device *dev = (&ili->panel)->dev;
0366     int ret = 0;
0367 
0368     /* Assert RESET */
0369     gpiod_set_value(ili->reset_gpio, 1);
0370 
0371     /* Enable power */
0372     ret = regulator_bulk_enable(ARRAY_SIZE(ili->supplies),
0373                     ili->supplies);
0374     if (ret < 0) {
0375         dev_err(dev, "unable to enable vcc\n");
0376         return ret;
0377     }
0378     msleep(20);
0379 
0380     /* De-assert RESET */
0381     gpiod_set_value(ili->reset_gpio, 0);
0382     msleep(20);
0383 
0384     return 0;
0385 }
0386 
0387 static int ili9341_dpi_power_off(struct ili9341 *ili)
0388 {
0389     /* Assert RESET */
0390     gpiod_set_value(ili->reset_gpio, 1);
0391 
0392     /* Disable power */
0393     return regulator_bulk_disable(ARRAY_SIZE(ili->supplies),
0394                       ili->supplies);
0395 }
0396 
0397 static int ili9341_dpi_disable(struct drm_panel *panel)
0398 {
0399     struct ili9341 *ili = panel_to_ili9341(panel);
0400 
0401     mipi_dbi_command(ili->dbi, MIPI_DCS_SET_DISPLAY_OFF);
0402     return 0;
0403 }
0404 
0405 static int ili9341_dpi_unprepare(struct drm_panel *panel)
0406 {
0407     struct ili9341 *ili = panel_to_ili9341(panel);
0408 
0409     return ili9341_dpi_power_off(ili);
0410 }
0411 
0412 static int ili9341_dpi_prepare(struct drm_panel *panel)
0413 {
0414     struct ili9341 *ili = panel_to_ili9341(panel);
0415     int ret;
0416 
0417     ret = ili9341_dpi_power_on(ili);
0418     if (ret < 0)
0419         return ret;
0420 
0421     ili9341_dpi_init(ili);
0422 
0423     return ret;
0424 }
0425 
0426 static int ili9341_dpi_enable(struct drm_panel *panel)
0427 {
0428     struct ili9341 *ili = panel_to_ili9341(panel);
0429 
0430     mipi_dbi_command(ili->dbi, MIPI_DCS_SET_DISPLAY_ON);
0431     return 0;
0432 }
0433 
0434 static int ili9341_dpi_get_modes(struct drm_panel *panel,
0435                  struct drm_connector *connector)
0436 {
0437     struct ili9341 *ili = panel_to_ili9341(panel);
0438     struct drm_device *drm = connector->dev;
0439     struct drm_display_mode *mode;
0440     struct drm_display_info *info;
0441 
0442     info = &connector->display_info;
0443     info->width_mm = ili->conf->mode.width_mm;
0444     info->height_mm = ili->conf->mode.height_mm;
0445 
0446     if (ili->conf->rgb_interface & ILI9341_RGB_DPL)
0447         info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
0448     else
0449         info->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
0450 
0451     if (ili->conf->rgb_interface & ILI9341_RGB_EPL)
0452         info->bus_flags |= DRM_BUS_FLAG_DE_LOW;
0453     else
0454         info->bus_flags |= DRM_BUS_FLAG_DE_HIGH;
0455 
0456     mode = drm_mode_duplicate(drm, &ili->conf->mode);
0457     if (!mode) {
0458         drm_err(drm, "bad mode or failed to add mode\n");
0459         return -EINVAL;
0460     }
0461     drm_mode_set_name(mode);
0462 
0463     /* Set up the polarity */
0464     if (ili->conf->rgb_interface & ILI9341_RGB_HSPL)
0465         mode->flags |= DRM_MODE_FLAG_PHSYNC;
0466     else
0467         mode->flags |= DRM_MODE_FLAG_NHSYNC;
0468 
0469     if (ili->conf->rgb_interface & ILI9341_RGB_VSPL)
0470         mode->flags |= DRM_MODE_FLAG_PVSYNC;
0471     else
0472         mode->flags |= DRM_MODE_FLAG_NVSYNC;
0473 
0474     drm_mode_probed_add(connector, mode);
0475 
0476     return 1; /* Number of modes */
0477 }
0478 
0479 static const struct drm_panel_funcs ili9341_dpi_funcs = {
0480     .disable = ili9341_dpi_disable,
0481     .unprepare = ili9341_dpi_unprepare,
0482     .prepare = ili9341_dpi_prepare,
0483     .enable = ili9341_dpi_enable,
0484     .get_modes = ili9341_dpi_get_modes,
0485 };
0486 
0487 static void ili9341_dbi_enable(struct drm_simple_display_pipe *pipe,
0488                    struct drm_crtc_state *crtc_state,
0489                    struct drm_plane_state *plane_state)
0490 {
0491     struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
0492     struct mipi_dbi *dbi = &dbidev->dbi;
0493     u8 addr_mode;
0494     int ret, idx;
0495 
0496     if (!drm_dev_enter(pipe->crtc.dev, &idx))
0497         return;
0498 
0499     ret = mipi_dbi_poweron_conditional_reset(dbidev);
0500     if (ret < 0)
0501         goto out_exit;
0502     if (ret == 1)
0503         goto out_enable;
0504 
0505     mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF);
0506 
0507     mipi_dbi_command(dbi, ILI9341_POWERB, 0x00, 0xc1, 0x30);
0508     mipi_dbi_command(dbi, ILI9341_POWER_SEQ, 0x64, 0x03, 0x12, 0x81);
0509     mipi_dbi_command(dbi, ILI9341_DTCA, 0x85, 0x00, 0x78);
0510     mipi_dbi_command(dbi, ILI9341_POWERA, 0x39, 0x2c, 0x00, 0x34, 0x02);
0511     mipi_dbi_command(dbi, ILI9341_PRC, ILI9341_DBI_PRC_NORMAL);
0512     mipi_dbi_command(dbi, ILI9341_DTCB, 0x00, 0x00);
0513 
0514     /* Power Control */
0515     mipi_dbi_command(dbi, ILI9341_POWER1, ILI9341_DBI_VCOMH_4P6V);
0516     mipi_dbi_command(dbi, ILI9341_POWER2, ILI9341_DBI_PWR_2_DEFAULT);
0517     /* VCOM */
0518     mipi_dbi_command(dbi, ILI9341_VCOM1, ILI9341_DBI_VCOM_1_VMH_4P25V,
0519              ILI9341_DBI_VCOM_1_VML_1P5V);
0520     mipi_dbi_command(dbi, ILI9341_VCOM2, ILI9341_DBI_VCOM_2_DEC_58);
0521 
0522     /* Memory Access Control */
0523     mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT,
0524              MIPI_DCS_PIXEL_FMT_16BIT);
0525 
0526     /* Frame Rate */
0527     mipi_dbi_command(dbi, ILI9341_FRC, ILI9341_DBI_FRC_DIVA & 0x03,
0528              ILI9341_DBI_FRC_RTNA & 0x1f);
0529 
0530     /* Gamma */
0531     mipi_dbi_command(dbi, ILI9341_3GAMMA_EN, 0x00);
0532     mipi_dbi_command(dbi, MIPI_DCS_SET_GAMMA_CURVE, ILI9341_GAMMA_CURVE_1);
0533     mipi_dbi_command(dbi, ILI9341_PGAMMA,
0534              0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e, 0xf1,
0535              0x37, 0x07, 0x10, 0x03, 0x0e, 0x09, 0x00);
0536     mipi_dbi_command(dbi, ILI9341_NGAMMA,
0537              0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31, 0xc1,
0538              0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36, 0x0f);
0539 
0540     /* DDRAM */
0541     mipi_dbi_command(dbi, ILI9341_ETMOD, ILI9341_DBI_EMS_GAS |
0542              ILI9341_DBI_EMS_DTS |
0543              ILI9341_DBI_EMS_GON);
0544 
0545     /* Display */
0546     mipi_dbi_command(dbi, ILI9341_DFC, 0x08, 0x82, 0x27, 0x00);
0547     mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
0548     msleep(100);
0549 
0550     mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
0551     msleep(100);
0552 
0553 out_enable:
0554     switch (dbidev->rotation) {
0555     default:
0556         addr_mode = ILI9341_MADCTL_MX;
0557         break;
0558     case 90:
0559         addr_mode = ILI9341_MADCTL_MV;
0560         break;
0561     case 180:
0562         addr_mode = ILI9341_MADCTL_MY;
0563         break;
0564     case 270:
0565         addr_mode = ILI9341_MADCTL_MV | ILI9341_MADCTL_MY |
0566                 ILI9341_MADCTL_MX;
0567         break;
0568     }
0569 
0570     addr_mode |= ILI9341_MADCTL_BGR;
0571     mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
0572     mipi_dbi_enable_flush(dbidev, crtc_state, plane_state);
0573     drm_info(&dbidev->drm, "Initialized display serial interface\n");
0574 out_exit:
0575     drm_dev_exit(idx);
0576 }
0577 
0578 static const struct drm_simple_display_pipe_funcs ili9341_dbi_funcs = {
0579     .enable = ili9341_dbi_enable,
0580     .disable = mipi_dbi_pipe_disable,
0581     .update = mipi_dbi_pipe_update,
0582     .prepare_fb = drm_gem_simple_display_pipe_prepare_fb,
0583 };
0584 
0585 static const struct drm_display_mode ili9341_dbi_mode = {
0586     DRM_SIMPLE_MODE(240, 320, 37, 49),
0587 };
0588 
0589 DEFINE_DRM_GEM_CMA_FOPS(ili9341_dbi_fops);
0590 
0591 static struct drm_driver ili9341_dbi_driver = {
0592     .driver_features    = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
0593     .fops           = &ili9341_dbi_fops,
0594     DRM_GEM_CMA_DRIVER_OPS_VMAP,
0595     .debugfs_init       = mipi_dbi_debugfs_init,
0596     .name           = "ili9341",
0597     .desc           = "Ilitek ILI9341",
0598     .date           = "20210716",
0599     .major          = 1,
0600     .minor          = 0,
0601 };
0602 
0603 static int ili9341_dbi_probe(struct spi_device *spi, struct gpio_desc *dc,
0604                  struct gpio_desc *reset)
0605 {
0606     struct device *dev = &spi->dev;
0607     struct mipi_dbi_dev *dbidev;
0608     struct mipi_dbi *dbi;
0609     struct drm_device *drm;
0610     struct regulator *vcc;
0611     u32 rotation = 0;
0612     int ret;
0613 
0614     vcc = devm_regulator_get_optional(dev, "vcc");
0615     if (IS_ERR(vcc)) {
0616         dev_err(dev, "get optional vcc failed\n");
0617         vcc = NULL;
0618     }
0619 
0620     dbidev = devm_drm_dev_alloc(dev, &ili9341_dbi_driver,
0621                     struct mipi_dbi_dev, drm);
0622     if (IS_ERR(dbidev))
0623         return PTR_ERR(dbidev);
0624 
0625     dbi = &dbidev->dbi;
0626     drm = &dbidev->drm;
0627     dbi->reset = reset;
0628     dbidev->regulator = vcc;
0629 
0630     drm_mode_config_init(drm);
0631 
0632     dbidev->backlight = devm_of_find_backlight(dev);
0633     if (IS_ERR(dbidev->backlight))
0634         return PTR_ERR(dbidev->backlight);
0635 
0636     device_property_read_u32(dev, "rotation", &rotation);
0637 
0638     ret = mipi_dbi_spi_init(spi, dbi, dc);
0639     if (ret)
0640         return ret;
0641 
0642     ret = mipi_dbi_dev_init(dbidev, &ili9341_dbi_funcs,
0643                 &ili9341_dbi_mode, rotation);
0644     if (ret)
0645         return ret;
0646 
0647     drm_mode_config_reset(drm);
0648 
0649     ret = drm_dev_register(drm, 0);
0650     if (ret)
0651         return ret;
0652 
0653     spi_set_drvdata(spi, drm);
0654 
0655     drm_fbdev_generic_setup(drm, 0);
0656 
0657     return 0;
0658 }
0659 
0660 static int ili9341_dpi_probe(struct spi_device *spi, struct gpio_desc *dc,
0661                  struct gpio_desc *reset)
0662 {
0663     struct device *dev = &spi->dev;
0664     struct ili9341 *ili;
0665     int ret;
0666 
0667     ili = devm_kzalloc(dev, sizeof(struct ili9341), GFP_KERNEL);
0668     if (!ili)
0669         return -ENOMEM;
0670 
0671     ili->dbi = devm_kzalloc(dev, sizeof(struct mipi_dbi),
0672                 GFP_KERNEL);
0673     if (!ili->dbi)
0674         return -ENOMEM;
0675 
0676     ili->supplies[0].supply = "vci";
0677     ili->supplies[1].supply = "vddi";
0678     ili->supplies[2].supply = "vddi-led";
0679     ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ili->supplies),
0680                       ili->supplies);
0681     if (ret < 0) {
0682         dev_err(dev, "failed to get regulators: %d\n", ret);
0683         return ret;
0684     }
0685 
0686     ret = mipi_dbi_spi_init(spi, ili->dbi, dc);
0687     if (ret)
0688         return ret;
0689 
0690     spi_set_drvdata(spi, ili);
0691     ili->reset_gpio = reset;
0692     /*
0693      * Every new incarnation of this display must have a unique
0694      * data entry for the system in this driver.
0695      */
0696     ili->conf = of_device_get_match_data(dev);
0697     if (!ili->conf) {
0698         dev_err(dev, "missing device configuration\n");
0699         return -ENODEV;
0700     }
0701 
0702     ili->max_spi_speed = ili->conf->max_spi_speed;
0703     drm_panel_init(&ili->panel, dev, &ili9341_dpi_funcs,
0704                DRM_MODE_CONNECTOR_DPI);
0705     drm_panel_add(&ili->panel);
0706 
0707     return 0;
0708 }
0709 
0710 static int ili9341_probe(struct spi_device *spi)
0711 {
0712     struct device *dev = &spi->dev;
0713     struct gpio_desc *dc;
0714     struct gpio_desc *reset;
0715     const struct spi_device_id *id = spi_get_device_id(spi);
0716 
0717     reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
0718     if (IS_ERR(reset))
0719         dev_err(dev, "Failed to get gpio 'reset'\n");
0720 
0721     dc = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW);
0722     if (IS_ERR(dc))
0723         dev_err(dev, "Failed to get gpio 'dc'\n");
0724 
0725     if (!strcmp(id->name, "sf-tc240t-9370-t"))
0726         return ili9341_dpi_probe(spi, dc, reset);
0727     else if (!strcmp(id->name, "yx240qv29"))
0728         return ili9341_dbi_probe(spi, dc, reset);
0729 
0730     return -1;
0731 }
0732 
0733 static void ili9341_remove(struct spi_device *spi)
0734 {
0735     const struct spi_device_id *id = spi_get_device_id(spi);
0736     struct ili9341 *ili = spi_get_drvdata(spi);
0737     struct drm_device *drm = spi_get_drvdata(spi);
0738 
0739     if (!strcmp(id->name, "sf-tc240t-9370-t")) {
0740         ili9341_dpi_power_off(ili);
0741         drm_panel_remove(&ili->panel);
0742     } else if (!strcmp(id->name, "yx240qv29")) {
0743         drm_dev_unplug(drm);
0744         drm_atomic_helper_shutdown(drm);
0745     }
0746 }
0747 
0748 static void ili9341_shutdown(struct spi_device *spi)
0749 {
0750     const struct spi_device_id *id = spi_get_device_id(spi);
0751 
0752     if (!strcmp(id->name, "yx240qv29"))
0753         drm_atomic_helper_shutdown(spi_get_drvdata(spi));
0754 }
0755 
0756 static const struct of_device_id ili9341_of_match[] = {
0757     {
0758         .compatible = "st,sf-tc240t-9370-t",
0759         .data = &ili9341_stm32f429_disco_data,
0760     },
0761     {
0762         /* porting from tiny/ili9341.c
0763          * for original mipi dbi compitable
0764          */
0765         .compatible = "adafruit,yx240qv29",
0766         .data = NULL,
0767     },
0768     { }
0769 };
0770 MODULE_DEVICE_TABLE(of, ili9341_of_match);
0771 
0772 static const struct spi_device_id ili9341_id[] = {
0773     { "yx240qv29", 0 },
0774     { "sf-tc240t-9370-t", 0 },
0775     { }
0776 };
0777 MODULE_DEVICE_TABLE(spi, ili9341_id);
0778 
0779 static struct spi_driver ili9341_driver = {
0780     .probe = ili9341_probe,
0781     .remove = ili9341_remove,
0782     .shutdown = ili9341_shutdown,
0783     .id_table = ili9341_id,
0784     .driver = {
0785         .name = "panel-ilitek-ili9341",
0786         .of_match_table = ili9341_of_match,
0787     },
0788 };
0789 module_spi_driver(ili9341_driver);
0790 
0791 MODULE_AUTHOR("Dillon Min <dillon.minfei@gmail.com>");
0792 MODULE_DESCRIPTION("ILI9341 LCD panel driver");
0793 MODULE_LICENSE("GPL v2");