cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

panel-tpo-tpg110.c (11352B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Panel driver for the TPO TPG110 400CH LTPS TFT LCD Single Chip
      4 * Digital Driver.
      5 *
      6 * This chip drives a TFT LCD, so it does not know what kind of
      7 * display is actually connected to it, so the width and height of that
      8 * display needs to be supplied from the machine configuration.
      9 *
     10 * Author:
     11 * Linus Walleij <linus.walleij@linaro.org>
     12 */
     13#include <drm/drm_modes.h>
     14#include <drm/drm_panel.h>
     15
     16#include <linux/bitops.h>
     17#include <linux/delay.h>
     18#include <linux/gpio/consumer.h>
     19#include <linux/init.h>
     20#include <linux/kernel.h>
     21#include <linux/module.h>
     22#include <linux/of.h>
     23#include <linux/platform_device.h>
     24#include <linux/spi/spi.h>
     25
     26#define TPG110_TEST			0x00
     27#define TPG110_CHIPID			0x01
     28#define TPG110_CTRL1			0x02
     29#define TPG110_RES_MASK			GENMASK(2, 0)
     30#define TPG110_RES_800X480		0x07
     31#define TPG110_RES_640X480		0x06
     32#define TPG110_RES_480X272		0x05
     33#define TPG110_RES_480X640		0x04
     34#define TPG110_RES_480X272_D		0x01 /* Dual scan: outputs 800x480 */
     35#define TPG110_RES_400X240_D		0x00 /* Dual scan: outputs 800x480 */
     36#define TPG110_CTRL2			0x03
     37#define TPG110_CTRL2_PM			BIT(0)
     38#define TPG110_CTRL2_RES_PM_CTRL	BIT(7)
     39
     40/**
     41 * struct tpg110_panel_mode - lookup struct for the supported modes
     42 */
     43struct tpg110_panel_mode {
     44	/**
     45	 * @name: the name of this panel
     46	 */
     47	const char *name;
     48	/**
     49	 * @magic: the magic value from the detection register
     50	 */
     51	u32 magic;
     52	/**
     53	 * @mode: the DRM display mode for this panel
     54	 */
     55	struct drm_display_mode mode;
     56	/**
     57	 * @bus_flags: the DRM bus flags for this panel e.g. inverted clock
     58	 */
     59	u32 bus_flags;
     60};
     61
     62/**
     63 * struct tpg110 - state container for the TPG110 panel
     64 */
     65struct tpg110 {
     66	/**
     67	 * @dev: the container device
     68	 */
     69	struct device *dev;
     70	/**
     71	 * @spi: the corresponding SPI device
     72	 */
     73	struct spi_device *spi;
     74	/**
     75	 * @panel: the DRM panel instance for this device
     76	 */
     77	struct drm_panel panel;
     78	/**
     79	 * @panel_mode: the panel mode as detected
     80	 */
     81	const struct tpg110_panel_mode *panel_mode;
     82	/**
     83	 * @width: the width of this panel in mm
     84	 */
     85	u32 width;
     86	/**
     87	 * @height: the height of this panel in mm
     88	 */
     89	u32 height;
     90	/**
     91	 * @grestb: reset GPIO line
     92	 */
     93	struct gpio_desc *grestb;
     94};
     95
     96/*
     97 * TPG110 modes, these are the simple modes, the dualscan modes that
     98 * take 400x240 or 480x272 in and display as 800x480 are not listed.
     99 */
    100static const struct tpg110_panel_mode tpg110_modes[] = {
    101	{
    102		.name = "800x480 RGB",
    103		.magic = TPG110_RES_800X480,
    104		.mode = {
    105			.clock = 33200,
    106			.hdisplay = 800,
    107			.hsync_start = 800 + 40,
    108			.hsync_end = 800 + 40 + 1,
    109			.htotal = 800 + 40 + 1 + 216,
    110			.vdisplay = 480,
    111			.vsync_start = 480 + 10,
    112			.vsync_end = 480 + 10 + 1,
    113			.vtotal = 480 + 10 + 1 + 35,
    114		},
    115		.bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
    116	},
    117	{
    118		.name = "640x480 RGB",
    119		.magic = TPG110_RES_640X480,
    120		.mode = {
    121			.clock = 25200,
    122			.hdisplay = 640,
    123			.hsync_start = 640 + 24,
    124			.hsync_end = 640 + 24 + 1,
    125			.htotal = 640 + 24 + 1 + 136,
    126			.vdisplay = 480,
    127			.vsync_start = 480 + 18,
    128			.vsync_end = 480 + 18 + 1,
    129			.vtotal = 480 + 18 + 1 + 27,
    130		},
    131		.bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
    132	},
    133	{
    134		.name = "480x272 RGB",
    135		.magic = TPG110_RES_480X272,
    136		.mode = {
    137			.clock = 9000,
    138			.hdisplay = 480,
    139			.hsync_start = 480 + 2,
    140			.hsync_end = 480 + 2 + 1,
    141			.htotal = 480 + 2 + 1 + 43,
    142			.vdisplay = 272,
    143			.vsync_start = 272 + 2,
    144			.vsync_end = 272 + 2 + 1,
    145			.vtotal = 272 + 2 + 1 + 12,
    146		},
    147		.bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
    148	},
    149	{
    150		.name = "480x640 RGB",
    151		.magic = TPG110_RES_480X640,
    152		.mode = {
    153			.clock = 20500,
    154			.hdisplay = 480,
    155			.hsync_start = 480 + 2,
    156			.hsync_end = 480 + 2 + 1,
    157			.htotal = 480 + 2 + 1 + 43,
    158			.vdisplay = 640,
    159			.vsync_start = 640 + 4,
    160			.vsync_end = 640 + 4 + 1,
    161			.vtotal = 640 + 4 + 1 + 8,
    162		},
    163		.bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
    164	},
    165	{
    166		.name = "400x240 RGB",
    167		.magic = TPG110_RES_400X240_D,
    168		.mode = {
    169			.clock = 8300,
    170			.hdisplay = 400,
    171			.hsync_start = 400 + 20,
    172			.hsync_end = 400 + 20 + 1,
    173			.htotal = 400 + 20 + 1 + 108,
    174			.vdisplay = 240,
    175			.vsync_start = 240 + 2,
    176			.vsync_end = 240 + 2 + 1,
    177			.vtotal = 240 + 2 + 1 + 20,
    178		},
    179		.bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
    180	},
    181};
    182
    183static inline struct tpg110 *
    184to_tpg110(struct drm_panel *panel)
    185{
    186	return container_of(panel, struct tpg110, panel);
    187}
    188
    189static u8 tpg110_readwrite_reg(struct tpg110 *tpg, bool write,
    190			       u8 address, u8 outval)
    191{
    192	struct spi_message m;
    193	struct spi_transfer t[2];
    194	u8 buf[2];
    195	int ret;
    196
    197	spi_message_init(&m);
    198	memset(t, 0, sizeof(t));
    199
    200	if (write) {
    201		/*
    202		 * Clear address bit 0, 1 when writing, just to be sure
    203		 * The actual bit indicating a write here is bit 1, bit
    204		 * 0 is just surplus to pad it up to 8 bits.
    205		 */
    206		buf[0] = address << 2;
    207		buf[0] &= ~0x03;
    208		buf[1] = outval;
    209
    210		t[0].bits_per_word = 8;
    211		t[0].tx_buf = &buf[0];
    212		t[0].len = 1;
    213
    214		t[1].tx_buf = &buf[1];
    215		t[1].len = 1;
    216		t[1].bits_per_word = 8;
    217	} else {
    218		/* Set address bit 0 to 1 to read */
    219		buf[0] = address << 1;
    220		buf[0] |= 0x01;
    221
    222		/*
    223		 * The last bit/clock is Hi-Z turnaround cycle, so we need
    224		 * to send only 7 bits here. The 8th bit is the high impedance
    225		 * turn-around cycle.
    226		 */
    227		t[0].bits_per_word = 7;
    228		t[0].tx_buf = &buf[0];
    229		t[0].len = 1;
    230
    231		t[1].rx_buf = &buf[1];
    232		t[1].len = 1;
    233		t[1].bits_per_word = 8;
    234	}
    235
    236	spi_message_add_tail(&t[0], &m);
    237	spi_message_add_tail(&t[1], &m);
    238	ret = spi_sync(tpg->spi, &m);
    239	if (ret) {
    240		dev_err(tpg->dev, "SPI message error %d\n", ret);
    241		return ret;
    242	}
    243	if (write)
    244		return 0;
    245	/* Read */
    246	return buf[1];
    247}
    248
    249static u8 tpg110_read_reg(struct tpg110 *tpg, u8 address)
    250{
    251	return tpg110_readwrite_reg(tpg, false, address, 0);
    252}
    253
    254static void tpg110_write_reg(struct tpg110 *tpg, u8 address, u8 outval)
    255{
    256	tpg110_readwrite_reg(tpg, true, address, outval);
    257}
    258
    259static int tpg110_startup(struct tpg110 *tpg)
    260{
    261	u8 val;
    262	int i;
    263
    264	/* De-assert the reset signal */
    265	gpiod_set_value_cansleep(tpg->grestb, 0);
    266	usleep_range(1000, 2000);
    267	dev_dbg(tpg->dev, "de-asserted GRESTB\n");
    268
    269	/* Test display communication */
    270	tpg110_write_reg(tpg, TPG110_TEST, 0x55);
    271	val = tpg110_read_reg(tpg, TPG110_TEST);
    272	if (val != 0x55) {
    273		dev_err(tpg->dev, "failed communication test\n");
    274		return -ENODEV;
    275	}
    276
    277	val = tpg110_read_reg(tpg, TPG110_CHIPID);
    278	dev_info(tpg->dev, "TPG110 chip ID: %d version: %d\n",
    279		 val >> 4, val & 0x0f);
    280
    281	/* Show display resolution */
    282	val = tpg110_read_reg(tpg, TPG110_CTRL1);
    283	val &= TPG110_RES_MASK;
    284	switch (val) {
    285	case TPG110_RES_400X240_D:
    286		dev_info(tpg->dev, "IN 400x240 RGB -> OUT 800x480 RGB (dual scan)\n");
    287		break;
    288	case TPG110_RES_480X272_D:
    289		dev_info(tpg->dev, "IN 480x272 RGB -> OUT 800x480 RGB (dual scan)\n");
    290		break;
    291	case TPG110_RES_480X640:
    292		dev_info(tpg->dev, "480x640 RGB\n");
    293		break;
    294	case TPG110_RES_480X272:
    295		dev_info(tpg->dev, "480x272 RGB\n");
    296		break;
    297	case TPG110_RES_640X480:
    298		dev_info(tpg->dev, "640x480 RGB\n");
    299		break;
    300	case TPG110_RES_800X480:
    301		dev_info(tpg->dev, "800x480 RGB\n");
    302		break;
    303	default:
    304		dev_err(tpg->dev, "ILLEGAL RESOLUTION 0x%02x\n", val);
    305		break;
    306	}
    307
    308	/* From the producer side, this is the same resolution */
    309	if (val == TPG110_RES_480X272_D)
    310		val = TPG110_RES_480X272;
    311
    312	for (i = 0; i < ARRAY_SIZE(tpg110_modes); i++) {
    313		const struct tpg110_panel_mode *pm;
    314
    315		pm = &tpg110_modes[i];
    316		if (pm->magic == val) {
    317			tpg->panel_mode = pm;
    318			break;
    319		}
    320	}
    321	if (i == ARRAY_SIZE(tpg110_modes)) {
    322		dev_err(tpg->dev, "unsupported mode (%02x) detected\n", val);
    323		return -ENODEV;
    324	}
    325
    326	val = tpg110_read_reg(tpg, TPG110_CTRL2);
    327	dev_info(tpg->dev, "resolution and standby is controlled by %s\n",
    328		 (val & TPG110_CTRL2_RES_PM_CTRL) ? "software" : "hardware");
    329	/* Take control over resolution and standby */
    330	val |= TPG110_CTRL2_RES_PM_CTRL;
    331	tpg110_write_reg(tpg, TPG110_CTRL2, val);
    332
    333	return 0;
    334}
    335
    336static int tpg110_disable(struct drm_panel *panel)
    337{
    338	struct tpg110 *tpg = to_tpg110(panel);
    339	u8 val;
    340
    341	/* Put chip into standby */
    342	val = tpg110_read_reg(tpg, TPG110_CTRL2_PM);
    343	val &= ~TPG110_CTRL2_PM;
    344	tpg110_write_reg(tpg, TPG110_CTRL2_PM, val);
    345
    346	return 0;
    347}
    348
    349static int tpg110_enable(struct drm_panel *panel)
    350{
    351	struct tpg110 *tpg = to_tpg110(panel);
    352	u8 val;
    353
    354	/* Take chip out of standby */
    355	val = tpg110_read_reg(tpg, TPG110_CTRL2_PM);
    356	val |= TPG110_CTRL2_PM;
    357	tpg110_write_reg(tpg, TPG110_CTRL2_PM, val);
    358
    359	return 0;
    360}
    361
    362/**
    363 * tpg110_get_modes() - return the appropriate mode
    364 * @panel: the panel to get the mode for
    365 * @connector: reference to the central DRM connector control structure
    366 *
    367 * This currently does not present a forest of modes, instead it
    368 * presents the mode that is configured for the system under use,
    369 * and which is detected by reading the registers of the display.
    370 */
    371static int tpg110_get_modes(struct drm_panel *panel,
    372			    struct drm_connector *connector)
    373{
    374	struct tpg110 *tpg = to_tpg110(panel);
    375	struct drm_display_mode *mode;
    376
    377	connector->display_info.width_mm = tpg->width;
    378	connector->display_info.height_mm = tpg->height;
    379	connector->display_info.bus_flags = tpg->panel_mode->bus_flags;
    380
    381	mode = drm_mode_duplicate(connector->dev, &tpg->panel_mode->mode);
    382	drm_mode_set_name(mode);
    383	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
    384
    385	mode->width_mm = tpg->width;
    386	mode->height_mm = tpg->height;
    387
    388	drm_mode_probed_add(connector, mode);
    389
    390	return 1;
    391}
    392
    393static const struct drm_panel_funcs tpg110_drm_funcs = {
    394	.disable = tpg110_disable,
    395	.enable = tpg110_enable,
    396	.get_modes = tpg110_get_modes,
    397};
    398
    399static int tpg110_probe(struct spi_device *spi)
    400{
    401	struct device *dev = &spi->dev;
    402	struct device_node *np = dev->of_node;
    403	struct tpg110 *tpg;
    404	int ret;
    405
    406	tpg = devm_kzalloc(dev, sizeof(*tpg), GFP_KERNEL);
    407	if (!tpg)
    408		return -ENOMEM;
    409	tpg->dev = dev;
    410
    411	/* We get the physical display dimensions from the DT */
    412	ret = of_property_read_u32(np, "width-mm", &tpg->width);
    413	if (ret)
    414		dev_err(dev, "no panel width specified\n");
    415	ret = of_property_read_u32(np, "height-mm", &tpg->height);
    416	if (ret)
    417		dev_err(dev, "no panel height specified\n");
    418
    419	/* This asserts the GRESTB signal, putting the display into reset */
    420	tpg->grestb = devm_gpiod_get(dev, "grestb", GPIOD_OUT_HIGH);
    421	if (IS_ERR(tpg->grestb)) {
    422		dev_err(dev, "no GRESTB GPIO\n");
    423		return -ENODEV;
    424	}
    425
    426	spi->bits_per_word = 8;
    427	spi->mode |= SPI_3WIRE_HIZ;
    428	ret = spi_setup(spi);
    429	if (ret < 0) {
    430		dev_err(dev, "spi setup failed.\n");
    431		return ret;
    432	}
    433	tpg->spi = spi;
    434
    435	ret = tpg110_startup(tpg);
    436	if (ret)
    437		return ret;
    438
    439	drm_panel_init(&tpg->panel, dev, &tpg110_drm_funcs,
    440		       DRM_MODE_CONNECTOR_DPI);
    441
    442	ret = drm_panel_of_backlight(&tpg->panel);
    443	if (ret)
    444		return ret;
    445
    446	spi_set_drvdata(spi, tpg);
    447
    448	drm_panel_add(&tpg->panel);
    449
    450	return 0;
    451}
    452
    453static void tpg110_remove(struct spi_device *spi)
    454{
    455	struct tpg110 *tpg = spi_get_drvdata(spi);
    456
    457	drm_panel_remove(&tpg->panel);
    458}
    459
    460static const struct of_device_id tpg110_match[] = {
    461	{ .compatible = "tpo,tpg110", },
    462	{},
    463};
    464MODULE_DEVICE_TABLE(of, tpg110_match);
    465
    466static struct spi_driver tpg110_driver = {
    467	.probe		= tpg110_probe,
    468	.remove		= tpg110_remove,
    469	.driver		= {
    470		.name	= "tpo-tpg110-panel",
    471		.of_match_table = tpg110_match,
    472	},
    473};
    474module_spi_driver(tpg110_driver);
    475
    476MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
    477MODULE_DESCRIPTION("TPO TPG110 panel driver");
    478MODULE_LICENSE("GPL v2");