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

ili9486.c (6956B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * DRM driver for Ilitek ILI9486 panels
      4 *
      5 * Copyright 2020 Kamlesh Gurudasani <kamlesh.gurudasani@gmail.com>
      6 */
      7
      8#include <linux/backlight.h>
      9#include <linux/delay.h>
     10#include <linux/gpio/consumer.h>
     11#include <linux/module.h>
     12#include <linux/property.h>
     13#include <linux/spi/spi.h>
     14
     15#include <video/mipi_display.h>
     16
     17#include <drm/drm_atomic_helper.h>
     18#include <drm/drm_drv.h>
     19#include <drm/drm_fb_helper.h>
     20#include <drm/drm_gem_atomic_helper.h>
     21#include <drm/drm_gem_cma_helper.h>
     22#include <drm/drm_managed.h>
     23#include <drm/drm_mipi_dbi.h>
     24#include <drm/drm_modeset_helper.h>
     25
     26#define ILI9486_ITFCTR1         0xb0
     27#define ILI9486_PWCTRL1         0xc2
     28#define ILI9486_VMCTRL1         0xc5
     29#define ILI9486_PGAMCTRL        0xe0
     30#define ILI9486_NGAMCTRL        0xe1
     31#define ILI9486_DGAMCTRL        0xe2
     32#define ILI9486_MADCTL_BGR      BIT(3)
     33#define ILI9486_MADCTL_MV       BIT(5)
     34#define ILI9486_MADCTL_MX       BIT(6)
     35#define ILI9486_MADCTL_MY       BIT(7)
     36
     37/*
     38 * The PiScreen/waveshare rpi-lcd-35 has a SPI to 16-bit parallel bus converter
     39 * in front of the  display controller. This means that 8-bit values have to be
     40 * transferred as 16-bit.
     41 */
     42static int waveshare_command(struct mipi_dbi *mipi, u8 *cmd, u8 *par,
     43			     size_t num)
     44{
     45	struct spi_device *spi = mipi->spi;
     46	void *data = par;
     47	u32 speed_hz;
     48	int i, ret;
     49	__be16 *buf;
     50
     51	buf = kmalloc(32 * sizeof(u16), GFP_KERNEL);
     52	if (!buf)
     53		return -ENOMEM;
     54
     55	/*
     56	 * The displays are Raspberry Pi HATs and connected to the 8-bit only
     57	 * SPI controller, so 16-bit command and parameters need byte swapping
     58	 * before being transferred as 8-bit on the big endian SPI bus.
     59	 * Pixel data bytes have already been swapped before this function is
     60	 * called.
     61	 */
     62	buf[0] = cpu_to_be16(*cmd);
     63	gpiod_set_value_cansleep(mipi->dc, 0);
     64	speed_hz = mipi_dbi_spi_cmd_max_speed(spi, 2);
     65	ret = mipi_dbi_spi_transfer(spi, speed_hz, 8, buf, 2);
     66	if (ret || !num)
     67		goto free;
     68
     69	/* 8-bit configuration data, not 16-bit pixel data */
     70	if (num <= 32) {
     71		for (i = 0; i < num; i++)
     72			buf[i] = cpu_to_be16(par[i]);
     73		num *= 2;
     74		speed_hz = mipi_dbi_spi_cmd_max_speed(spi, num);
     75		data = buf;
     76	}
     77
     78	gpiod_set_value_cansleep(mipi->dc, 1);
     79	ret = mipi_dbi_spi_transfer(spi, speed_hz, 8, data, num);
     80 free:
     81	kfree(buf);
     82
     83	return ret;
     84}
     85
     86static void waveshare_enable(struct drm_simple_display_pipe *pipe,
     87			     struct drm_crtc_state *crtc_state,
     88			     struct drm_plane_state *plane_state)
     89{
     90	struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
     91	struct mipi_dbi *dbi = &dbidev->dbi;
     92	u8 addr_mode;
     93	int ret, idx;
     94
     95	if (!drm_dev_enter(pipe->crtc.dev, &idx))
     96		return;
     97
     98	DRM_DEBUG_KMS("\n");
     99
    100	ret = mipi_dbi_poweron_conditional_reset(dbidev);
    101	if (ret < 0)
    102		goto out_exit;
    103	if (ret == 1)
    104		goto out_enable;
    105
    106	mipi_dbi_command(dbi, ILI9486_ITFCTR1);
    107	mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
    108	msleep(250);
    109
    110	mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, 0x55);
    111
    112	mipi_dbi_command(dbi, ILI9486_PWCTRL1, 0x44);
    113
    114	mipi_dbi_command(dbi, ILI9486_VMCTRL1, 0x00, 0x00, 0x00, 0x00);
    115
    116	mipi_dbi_command(dbi, ILI9486_PGAMCTRL,
    117			 0x0F, 0x1F, 0x1C, 0x0C, 0x0F, 0x08, 0x48, 0x98,
    118			 0x37, 0x0A, 0x13, 0x04, 0x11, 0x0D, 0x0);
    119	mipi_dbi_command(dbi, ILI9486_NGAMCTRL,
    120			 0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75,
    121			 0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00);
    122	mipi_dbi_command(dbi, ILI9486_DGAMCTRL,
    123			 0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75,
    124			 0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00);
    125
    126	mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
    127	msleep(100);
    128
    129 out_enable:
    130	switch (dbidev->rotation) {
    131	case 90:
    132		addr_mode = ILI9486_MADCTL_MY;
    133		break;
    134	case 180:
    135		addr_mode = ILI9486_MADCTL_MV;
    136		break;
    137	case 270:
    138		addr_mode = ILI9486_MADCTL_MX;
    139		break;
    140	default:
    141		addr_mode = ILI9486_MADCTL_MV | ILI9486_MADCTL_MY |
    142			ILI9486_MADCTL_MX;
    143		break;
    144	}
    145	addr_mode |= ILI9486_MADCTL_BGR;
    146	mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
    147	mipi_dbi_enable_flush(dbidev, crtc_state, plane_state);
    148 out_exit:
    149	drm_dev_exit(idx);
    150}
    151
    152static const struct drm_simple_display_pipe_funcs waveshare_pipe_funcs = {
    153	.enable = waveshare_enable,
    154	.disable = mipi_dbi_pipe_disable,
    155	.update = mipi_dbi_pipe_update,
    156};
    157
    158static const struct drm_display_mode waveshare_mode = {
    159	DRM_SIMPLE_MODE(480, 320, 73, 49),
    160};
    161
    162DEFINE_DRM_GEM_CMA_FOPS(ili9486_fops);
    163
    164static const struct drm_driver ili9486_driver = {
    165	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
    166	.fops			= &ili9486_fops,
    167	DRM_GEM_CMA_DRIVER_OPS_VMAP,
    168	.debugfs_init		= mipi_dbi_debugfs_init,
    169	.name			= "ili9486",
    170	.desc			= "Ilitek ILI9486",
    171	.date			= "20200118",
    172	.major			= 1,
    173	.minor			= 0,
    174};
    175
    176static const struct of_device_id ili9486_of_match[] = {
    177	{ .compatible = "waveshare,rpi-lcd-35" },
    178	{ .compatible = "ozzmaker,piscreen" },
    179	{},
    180};
    181MODULE_DEVICE_TABLE(of, ili9486_of_match);
    182
    183static const struct spi_device_id ili9486_id[] = {
    184	{ "ili9486", 0 },
    185	{ }
    186};
    187MODULE_DEVICE_TABLE(spi, ili9486_id);
    188
    189static int ili9486_probe(struct spi_device *spi)
    190{
    191	struct device *dev = &spi->dev;
    192	struct mipi_dbi_dev *dbidev;
    193	struct drm_device *drm;
    194	struct mipi_dbi *dbi;
    195	struct gpio_desc *dc;
    196	u32 rotation = 0;
    197	int ret;
    198
    199	dbidev = devm_drm_dev_alloc(dev, &ili9486_driver,
    200				    struct mipi_dbi_dev, drm);
    201	if (IS_ERR(dbidev))
    202		return PTR_ERR(dbidev);
    203
    204	dbi = &dbidev->dbi;
    205	drm = &dbidev->drm;
    206
    207	dbi->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
    208	if (IS_ERR(dbi->reset))
    209		return dev_err_probe(dev, PTR_ERR(dbi->reset), "Failed to get GPIO 'reset'\n");
    210
    211	dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW);
    212	if (IS_ERR(dc))
    213		return dev_err_probe(dev, PTR_ERR(dc), "Failed to get GPIO 'dc'\n");
    214
    215	dbidev->backlight = devm_of_find_backlight(dev);
    216	if (IS_ERR(dbidev->backlight))
    217		return PTR_ERR(dbidev->backlight);
    218
    219	device_property_read_u32(dev, "rotation", &rotation);
    220
    221	ret = mipi_dbi_spi_init(spi, dbi, dc);
    222	if (ret)
    223		return ret;
    224
    225	dbi->command = waveshare_command;
    226	dbi->read_commands = NULL;
    227
    228	ret = mipi_dbi_dev_init(dbidev, &waveshare_pipe_funcs,
    229				&waveshare_mode, rotation);
    230	if (ret)
    231		return ret;
    232
    233	drm_mode_config_reset(drm);
    234
    235	ret = drm_dev_register(drm, 0);
    236	if (ret)
    237		return ret;
    238
    239	spi_set_drvdata(spi, drm);
    240
    241	drm_fbdev_generic_setup(drm, 0);
    242
    243	return 0;
    244}
    245
    246static void ili9486_remove(struct spi_device *spi)
    247{
    248	struct drm_device *drm = spi_get_drvdata(spi);
    249
    250	drm_dev_unplug(drm);
    251	drm_atomic_helper_shutdown(drm);
    252}
    253
    254static void ili9486_shutdown(struct spi_device *spi)
    255{
    256	drm_atomic_helper_shutdown(spi_get_drvdata(spi));
    257}
    258
    259static struct spi_driver ili9486_spi_driver = {
    260	.driver = {
    261		.name = "ili9486",
    262		.of_match_table = ili9486_of_match,
    263	},
    264	.id_table = ili9486_id,
    265	.probe = ili9486_probe,
    266	.remove = ili9486_remove,
    267	.shutdown = ili9486_shutdown,
    268};
    269module_spi_driver(ili9486_spi_driver);
    270
    271MODULE_DESCRIPTION("Ilitek ILI9486 DRM driver");
    272MODULE_AUTHOR("Kamlesh Gurudasani <kamlesh.gurudasani@gmail.com>");
    273MODULE_LICENSE("GPL");