Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/panel: sitronix-st7789v: Check display ID

A very basic debugging rule when a device is connected for the first
time is to access a read-only register which contains known data in
order to ensure the communication protocol is properly working. This
driver lacked any read helper which is often a critical piece for
speeding-up bring-ups.

Add a read helper and use it to verify the communication with the panel
is working as soon as possible in order to inform the user early if this
is not the case.

As this panel may work with no MISO line, the check is discarded in this
case. Upon error, we do not fail probing but just warn the user, in case
the DT description would be lacking the Rx bus width (which is likely on
old descriptions) in order to avoid breaking existing devices.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Acked-by: Sam Ravnborg <sam@ravnborg.org>
Acked-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Sebastian Reichel <sre@kernel.org>
Tested-by: Sebastian Reichel <sre@kernel.org> # no MISO line
Signed-off-by: Sebastian Reichel <sre@kernel.org>
Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20230714013756.1546769-20-sre@kernel.org

authored by

Miquel Raynal and committed by
Neil Armstrong
290cdd79 71f73908

+81
+81
drivers/gpu/drm/panel/panel-sitronix-st7789v.c
··· 110 110 return val; \ 111 111 } while (0) 112 112 113 + #define ST7789V_IDS { 0x85, 0x85, 0x52 } 114 + #define ST7789V_IDS_SIZE 3 115 + 113 116 struct st7789_panel_info { 114 117 const struct drm_display_mode *mode; 115 118 u32 bus_format; ··· 158 155 static int st7789v_write_data(struct st7789v *ctx, u8 cmd) 159 156 { 160 157 return st7789v_spi_write(ctx, ST7789V_DATA, cmd); 158 + } 159 + 160 + static int st7789v_read_data(struct st7789v *ctx, u8 cmd, u8 *buf, 161 + unsigned int len) 162 + { 163 + struct spi_transfer xfer[2] = { }; 164 + struct spi_message msg; 165 + u16 txbuf = ((ST7789V_COMMAND & 1) << 8) | cmd; 166 + u16 rxbuf[4] = {}; 167 + u8 bit9 = 0; 168 + int ret, i; 169 + 170 + switch (len) { 171 + case 1: 172 + case 3: 173 + case 4: 174 + break; 175 + default: 176 + return -EOPNOTSUPP; 177 + } 178 + 179 + spi_message_init(&msg); 180 + 181 + xfer[0].tx_buf = &txbuf; 182 + xfer[0].len = sizeof(txbuf); 183 + spi_message_add_tail(&xfer[0], &msg); 184 + 185 + xfer[1].rx_buf = rxbuf; 186 + xfer[1].len = len * 2; 187 + spi_message_add_tail(&xfer[1], &msg); 188 + 189 + ret = spi_sync(ctx->spi, &msg); 190 + if (ret) 191 + return ret; 192 + 193 + for (i = 0; i < len; i++) { 194 + buf[i] = rxbuf[i] >> i | (bit9 << (9 - i)); 195 + if (i) 196 + bit9 = rxbuf[i] & GENMASK(i - 1, 0); 197 + } 198 + 199 + return 0; 200 + } 201 + 202 + static int st7789v_check_id(struct drm_panel *panel) 203 + { 204 + const u8 st7789v_ids[ST7789V_IDS_SIZE] = ST7789V_IDS; 205 + struct st7789v *ctx = panel_to_st7789v(panel); 206 + bool invalid_ids = false; 207 + int ret, i; 208 + u8 ids[3]; 209 + 210 + if (ctx->spi->mode & SPI_NO_RX) 211 + return 0; 212 + 213 + ret = st7789v_read_data(ctx, MIPI_DCS_GET_DISPLAY_ID, ids, ST7789V_IDS_SIZE); 214 + if (ret) 215 + return ret; 216 + 217 + for (i = 0; i < ST7789V_IDS_SIZE; i++) { 218 + if (ids[i] != st7789v_ids[i]) { 219 + invalid_ids = true; 220 + break; 221 + } 222 + } 223 + 224 + if (invalid_ids) 225 + return -EIO; 226 + 227 + return 0; 161 228 } 162 229 163 230 static const struct drm_display_mode default_mode = { ··· 367 294 msleep(30); 368 295 gpiod_set_value(ctx->reset, 0); 369 296 msleep(120); 297 + 298 + /* 299 + * Avoid failing if the IDs are invalid in case the Rx bus width 300 + * description is missing. 301 + */ 302 + ret = st7789v_check_id(panel); 303 + if (ret) 304 + dev_warn(panel->dev, "Unrecognized panel IDs"); 370 305 371 306 ST7789V_TEST(ret, st7789v_write_command(ctx, MIPI_DCS_EXIT_SLEEP_MODE)); 372 307