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

ssd130x.c (26525B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * DRM driver for Solomon SSD130x OLED displays
      4 *
      5 * Copyright 2022 Red Hat Inc.
      6 * Author: Javier Martinez Canillas <javierm@redhat.com>
      7 *
      8 * Based on drivers/video/fbdev/ssd1307fb.c
      9 * Copyright 2012 Free Electrons
     10 */
     11
     12#include <linux/backlight.h>
     13#include <linux/bitfield.h>
     14#include <linux/bits.h>
     15#include <linux/delay.h>
     16#include <linux/gpio/consumer.h>
     17#include <linux/property.h>
     18#include <linux/pwm.h>
     19#include <linux/regulator/consumer.h>
     20
     21#include <drm/drm_atomic_helper.h>
     22#include <drm/drm_damage_helper.h>
     23#include <drm/drm_fb_cma_helper.h>
     24#include <drm/drm_fb_helper.h>
     25#include <drm/drm_format_helper.h>
     26#include <drm/drm_gem_atomic_helper.h>
     27#include <drm/drm_gem_framebuffer_helper.h>
     28#include <drm/drm_gem_shmem_helper.h>
     29#include <drm/drm_managed.h>
     30#include <drm/drm_modes.h>
     31#include <drm/drm_rect.h>
     32#include <drm/drm_probe_helper.h>
     33
     34#include "ssd130x.h"
     35
     36#define DRIVER_NAME	"ssd130x"
     37#define DRIVER_DESC	"DRM driver for Solomon SSD130x OLED displays"
     38#define DRIVER_DATE	"20220131"
     39#define DRIVER_MAJOR	1
     40#define DRIVER_MINOR	0
     41
     42#define SSD130X_PAGE_COL_START_LOW		0x00
     43#define SSD130X_PAGE_COL_START_HIGH		0x10
     44#define SSD130X_SET_ADDRESS_MODE		0x20
     45#define SSD130X_SET_COL_RANGE			0x21
     46#define SSD130X_SET_PAGE_RANGE			0x22
     47#define SSD130X_CONTRAST			0x81
     48#define SSD130X_SET_LOOKUP_TABLE		0x91
     49#define SSD130X_CHARGE_PUMP			0x8d
     50#define SSD130X_SET_SEG_REMAP			0xa0
     51#define SSD130X_DISPLAY_OFF			0xae
     52#define SSD130X_SET_MULTIPLEX_RATIO		0xa8
     53#define SSD130X_DISPLAY_ON			0xaf
     54#define SSD130X_START_PAGE_ADDRESS		0xb0
     55#define SSD130X_SET_COM_SCAN_DIR		0xc0
     56#define SSD130X_SET_DISPLAY_OFFSET		0xd3
     57#define SSD130X_SET_CLOCK_FREQ			0xd5
     58#define SSD130X_SET_AREA_COLOR_MODE		0xd8
     59#define SSD130X_SET_PRECHARGE_PERIOD		0xd9
     60#define SSD130X_SET_COM_PINS_CONFIG		0xda
     61#define SSD130X_SET_VCOMH			0xdb
     62
     63#define SSD130X_PAGE_COL_START_MASK		GENMASK(3, 0)
     64#define SSD130X_PAGE_COL_START_HIGH_SET(val)	FIELD_PREP(SSD130X_PAGE_COL_START_MASK, (val) >> 4)
     65#define SSD130X_PAGE_COL_START_LOW_SET(val)	FIELD_PREP(SSD130X_PAGE_COL_START_MASK, (val))
     66#define SSD130X_START_PAGE_ADDRESS_MASK		GENMASK(2, 0)
     67#define SSD130X_START_PAGE_ADDRESS_SET(val)	FIELD_PREP(SSD130X_START_PAGE_ADDRESS_MASK, (val))
     68#define SSD130X_SET_SEG_REMAP_MASK		GENMASK(0, 0)
     69#define SSD130X_SET_SEG_REMAP_SET(val)		FIELD_PREP(SSD130X_SET_SEG_REMAP_MASK, (val))
     70#define SSD130X_SET_COM_SCAN_DIR_MASK		GENMASK(3, 3)
     71#define SSD130X_SET_COM_SCAN_DIR_SET(val)	FIELD_PREP(SSD130X_SET_COM_SCAN_DIR_MASK, (val))
     72#define SSD130X_SET_CLOCK_DIV_MASK		GENMASK(3, 0)
     73#define SSD130X_SET_CLOCK_DIV_SET(val)		FIELD_PREP(SSD130X_SET_CLOCK_DIV_MASK, (val))
     74#define SSD130X_SET_CLOCK_FREQ_MASK		GENMASK(7, 4)
     75#define SSD130X_SET_CLOCK_FREQ_SET(val)		FIELD_PREP(SSD130X_SET_CLOCK_FREQ_MASK, (val))
     76#define SSD130X_SET_PRECHARGE_PERIOD1_MASK	GENMASK(3, 0)
     77#define SSD130X_SET_PRECHARGE_PERIOD1_SET(val)	FIELD_PREP(SSD130X_SET_PRECHARGE_PERIOD1_MASK, (val))
     78#define SSD130X_SET_PRECHARGE_PERIOD2_MASK	GENMASK(7, 4)
     79#define SSD130X_SET_PRECHARGE_PERIOD2_SET(val)	FIELD_PREP(SSD130X_SET_PRECHARGE_PERIOD2_MASK, (val))
     80#define SSD130X_SET_COM_PINS_CONFIG1_MASK	GENMASK(4, 4)
     81#define SSD130X_SET_COM_PINS_CONFIG1_SET(val)	FIELD_PREP(SSD130X_SET_COM_PINS_CONFIG1_MASK, !(val))
     82#define SSD130X_SET_COM_PINS_CONFIG2_MASK	GENMASK(5, 5)
     83#define SSD130X_SET_COM_PINS_CONFIG2_SET(val)	FIELD_PREP(SSD130X_SET_COM_PINS_CONFIG2_MASK, (val))
     84
     85#define SSD130X_SET_ADDRESS_MODE_HORIZONTAL	0x00
     86#define SSD130X_SET_ADDRESS_MODE_VERTICAL	0x01
     87#define SSD130X_SET_ADDRESS_MODE_PAGE		0x02
     88
     89#define SSD130X_SET_AREA_COLOR_MODE_ENABLE	0x1e
     90#define SSD130X_SET_AREA_COLOR_MODE_LOW_POWER	0x05
     91
     92#define MAX_CONTRAST 255
     93
     94const struct ssd130x_deviceinfo ssd130x_variants[] = {
     95	[SH1106_ID] = {
     96		.default_vcomh = 0x40,
     97		.default_dclk_div = 1,
     98		.default_dclk_frq = 5,
     99		.page_mode_only = 1,
    100	},
    101	[SSD1305_ID] = {
    102		.default_vcomh = 0x34,
    103		.default_dclk_div = 1,
    104		.default_dclk_frq = 7,
    105	},
    106	[SSD1306_ID] = {
    107		.default_vcomh = 0x20,
    108		.default_dclk_div = 1,
    109		.default_dclk_frq = 8,
    110		.need_chargepump = 1,
    111	},
    112	[SSD1307_ID] = {
    113		.default_vcomh = 0x20,
    114		.default_dclk_div = 2,
    115		.default_dclk_frq = 12,
    116		.need_pwm = 1,
    117	},
    118	[SSD1309_ID] = {
    119		.default_vcomh = 0x34,
    120		.default_dclk_div = 1,
    121		.default_dclk_frq = 10,
    122	}
    123};
    124EXPORT_SYMBOL_NS_GPL(ssd130x_variants, DRM_SSD130X);
    125
    126static inline struct ssd130x_device *drm_to_ssd130x(struct drm_device *drm)
    127{
    128	return container_of(drm, struct ssd130x_device, drm);
    129}
    130
    131/*
    132 * Helper to write data (SSD130X_DATA) to the device.
    133 */
    134static int ssd130x_write_data(struct ssd130x_device *ssd130x, u8 *values, int count)
    135{
    136	return regmap_bulk_write(ssd130x->regmap, SSD130X_DATA, values, count);
    137}
    138
    139/*
    140 * Helper to write command (SSD130X_COMMAND). The fist variadic argument
    141 * is the command to write and the following are the command options.
    142 *
    143 * Note that the ssd130x protocol requires each command and option to be
    144 * written as a SSD130X_COMMAND device register value. That is why a call
    145 * to regmap_write(..., SSD130X_COMMAND, ...) is done for each argument.
    146 */
    147static int ssd130x_write_cmd(struct ssd130x_device *ssd130x, int count,
    148			     /* u8 cmd, u8 option, ... */...)
    149{
    150	va_list ap;
    151	u8 value;
    152	int ret;
    153
    154	va_start(ap, count);
    155
    156	do {
    157		value = va_arg(ap, int);
    158		ret = regmap_write(ssd130x->regmap, SSD130X_COMMAND, value);
    159		if (ret)
    160			goto out_end;
    161	} while (--count);
    162
    163out_end:
    164	va_end(ap);
    165
    166	return ret;
    167}
    168
    169/* Set address range for horizontal/vertical addressing modes */
    170static int ssd130x_set_col_range(struct ssd130x_device *ssd130x,
    171				 u8 col_start, u8 cols)
    172{
    173	u8 col_end = col_start + cols - 1;
    174	int ret;
    175
    176	if (col_start == ssd130x->col_start && col_end == ssd130x->col_end)
    177		return 0;
    178
    179	ret = ssd130x_write_cmd(ssd130x, 3, SSD130X_SET_COL_RANGE, col_start, col_end);
    180	if (ret < 0)
    181		return ret;
    182
    183	ssd130x->col_start = col_start;
    184	ssd130x->col_end = col_end;
    185	return 0;
    186}
    187
    188static int ssd130x_set_page_range(struct ssd130x_device *ssd130x,
    189				  u8 page_start, u8 pages)
    190{
    191	u8 page_end = page_start + pages - 1;
    192	int ret;
    193
    194	if (page_start == ssd130x->page_start && page_end == ssd130x->page_end)
    195		return 0;
    196
    197	ret = ssd130x_write_cmd(ssd130x, 3, SSD130X_SET_PAGE_RANGE, page_start, page_end);
    198	if (ret < 0)
    199		return ret;
    200
    201	ssd130x->page_start = page_start;
    202	ssd130x->page_end = page_end;
    203	return 0;
    204}
    205
    206/* Set page and column start address for page addressing mode */
    207static int ssd130x_set_page_pos(struct ssd130x_device *ssd130x,
    208				u8 page_start, u8 col_start)
    209{
    210	int ret;
    211	u32 page, col_low, col_high;
    212
    213	page = SSD130X_START_PAGE_ADDRESS |
    214	       SSD130X_START_PAGE_ADDRESS_SET(page_start);
    215	col_low = SSD130X_PAGE_COL_START_LOW |
    216		  SSD130X_PAGE_COL_START_LOW_SET(col_start);
    217	col_high = SSD130X_PAGE_COL_START_HIGH |
    218		   SSD130X_PAGE_COL_START_HIGH_SET(col_start);
    219	ret = ssd130x_write_cmd(ssd130x, 3, page, col_low, col_high);
    220	if (ret < 0)
    221		return ret;
    222
    223	return 0;
    224}
    225
    226static int ssd130x_pwm_enable(struct ssd130x_device *ssd130x)
    227{
    228	struct device *dev = ssd130x->dev;
    229	struct pwm_state pwmstate;
    230
    231	ssd130x->pwm = pwm_get(dev, NULL);
    232	if (IS_ERR(ssd130x->pwm)) {
    233		dev_err(dev, "Could not get PWM from firmware description!\n");
    234		return PTR_ERR(ssd130x->pwm);
    235	}
    236
    237	pwm_init_state(ssd130x->pwm, &pwmstate);
    238	pwm_set_relative_duty_cycle(&pwmstate, 50, 100);
    239	pwm_apply_state(ssd130x->pwm, &pwmstate);
    240
    241	/* Enable the PWM */
    242	pwm_enable(ssd130x->pwm);
    243
    244	dev_dbg(dev, "Using PWM%d with a %lluns period.\n",
    245		ssd130x->pwm->pwm, pwm_get_period(ssd130x->pwm));
    246
    247	return 0;
    248}
    249
    250static void ssd130x_reset(struct ssd130x_device *ssd130x)
    251{
    252	if (!ssd130x->reset)
    253		return;
    254
    255	/* Reset the screen */
    256	gpiod_set_value_cansleep(ssd130x->reset, 1);
    257	udelay(4);
    258	gpiod_set_value_cansleep(ssd130x->reset, 0);
    259	udelay(4);
    260}
    261
    262static int ssd130x_power_on(struct ssd130x_device *ssd130x)
    263{
    264	struct device *dev = ssd130x->dev;
    265	int ret;
    266
    267	ssd130x_reset(ssd130x);
    268
    269	ret = regulator_enable(ssd130x->vcc_reg);
    270	if (ret) {
    271		dev_err(dev, "Failed to enable VCC: %d\n", ret);
    272		return ret;
    273	}
    274
    275	if (ssd130x->device_info->need_pwm) {
    276		ret = ssd130x_pwm_enable(ssd130x);
    277		if (ret) {
    278			dev_err(dev, "Failed to enable PWM: %d\n", ret);
    279			regulator_disable(ssd130x->vcc_reg);
    280			return ret;
    281		}
    282	}
    283
    284	return 0;
    285}
    286
    287static void ssd130x_power_off(struct ssd130x_device *ssd130x)
    288{
    289	pwm_disable(ssd130x->pwm);
    290	pwm_put(ssd130x->pwm);
    291
    292	regulator_disable(ssd130x->vcc_reg);
    293}
    294
    295static int ssd130x_init(struct ssd130x_device *ssd130x)
    296{
    297	u32 precharge, dclk, com_invdir, compins, chargepump, seg_remap;
    298	int ret;
    299
    300	/* Set initial contrast */
    301	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_CONTRAST, ssd130x->contrast);
    302	if (ret < 0)
    303		return ret;
    304
    305	/* Set segment re-map */
    306	seg_remap = (SSD130X_SET_SEG_REMAP |
    307		     SSD130X_SET_SEG_REMAP_SET(ssd130x->seg_remap));
    308	ret = ssd130x_write_cmd(ssd130x, 1, seg_remap);
    309	if (ret < 0)
    310		return ret;
    311
    312	/* Set COM direction */
    313	com_invdir = (SSD130X_SET_COM_SCAN_DIR |
    314		      SSD130X_SET_COM_SCAN_DIR_SET(ssd130x->com_invdir));
    315	ret = ssd130x_write_cmd(ssd130x,  1, com_invdir);
    316	if (ret < 0)
    317		return ret;
    318
    319	/* Set multiplex ratio value */
    320	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_MULTIPLEX_RATIO, ssd130x->height - 1);
    321	if (ret < 0)
    322		return ret;
    323
    324	/* set display offset value */
    325	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_DISPLAY_OFFSET, ssd130x->com_offset);
    326	if (ret < 0)
    327		return ret;
    328
    329	/* Set clock frequency */
    330	dclk = (SSD130X_SET_CLOCK_DIV_SET(ssd130x->dclk_div - 1) |
    331		SSD130X_SET_CLOCK_FREQ_SET(ssd130x->dclk_frq));
    332	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_CLOCK_FREQ, dclk);
    333	if (ret < 0)
    334		return ret;
    335
    336	/* Set Area Color Mode ON/OFF & Low Power Display Mode */
    337	if (ssd130x->area_color_enable || ssd130x->low_power) {
    338		u32 mode = 0;
    339
    340		if (ssd130x->area_color_enable)
    341			mode |= SSD130X_SET_AREA_COLOR_MODE_ENABLE;
    342
    343		if (ssd130x->low_power)
    344			mode |= SSD130X_SET_AREA_COLOR_MODE_LOW_POWER;
    345
    346		ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_AREA_COLOR_MODE, mode);
    347		if (ret < 0)
    348			return ret;
    349	}
    350
    351	/* Set precharge period in number of ticks from the internal clock */
    352	precharge = (SSD130X_SET_PRECHARGE_PERIOD1_SET(ssd130x->prechargep1) |
    353		     SSD130X_SET_PRECHARGE_PERIOD1_SET(ssd130x->prechargep2));
    354	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_PRECHARGE_PERIOD, precharge);
    355	if (ret < 0)
    356		return ret;
    357
    358	/* Set COM pins configuration */
    359	compins = BIT(1);
    360	compins |= (SSD130X_SET_COM_PINS_CONFIG1_SET(ssd130x->com_seq) |
    361		    SSD130X_SET_COM_PINS_CONFIG2_SET(ssd130x->com_lrremap));
    362	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_COM_PINS_CONFIG, compins);
    363	if (ret < 0)
    364		return ret;
    365
    366	/* Set VCOMH */
    367	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_VCOMH, ssd130x->vcomh);
    368	if (ret < 0)
    369		return ret;
    370
    371	/* Turn on the DC-DC Charge Pump */
    372	chargepump = BIT(4);
    373
    374	if (ssd130x->device_info->need_chargepump)
    375		chargepump |= BIT(2);
    376
    377	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_CHARGE_PUMP, chargepump);
    378	if (ret < 0)
    379		return ret;
    380
    381	/* Set lookup table */
    382	if (ssd130x->lookup_table_set) {
    383		int i;
    384
    385		ret = ssd130x_write_cmd(ssd130x, 1, SSD130X_SET_LOOKUP_TABLE);
    386		if (ret < 0)
    387			return ret;
    388
    389		for (i = 0; i < ARRAY_SIZE(ssd130x->lookup_table); i++) {
    390			u8 val = ssd130x->lookup_table[i];
    391
    392			if (val < 31 || val > 63)
    393				dev_warn(ssd130x->dev,
    394					 "lookup table index %d value out of range 31 <= %d <= 63\n",
    395					 i, val);
    396			ret = ssd130x_write_cmd(ssd130x, 1, val);
    397			if (ret < 0)
    398				return ret;
    399		}
    400	}
    401
    402	/* Switch to page addressing mode */
    403	if (ssd130x->page_address_mode)
    404		return ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_ADDRESS_MODE,
    405					 SSD130X_SET_ADDRESS_MODE_PAGE);
    406
    407	/* Switch to horizontal addressing mode */
    408	return ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_ADDRESS_MODE,
    409				 SSD130X_SET_ADDRESS_MODE_HORIZONTAL);
    410}
    411
    412static int ssd130x_update_rect(struct ssd130x_device *ssd130x, u8 *buf,
    413			       struct drm_rect *rect)
    414{
    415	unsigned int x = rect->x1;
    416	unsigned int y = rect->y1;
    417	unsigned int width = drm_rect_width(rect);
    418	unsigned int height = drm_rect_height(rect);
    419	unsigned int line_length = DIV_ROUND_UP(width, 8);
    420	unsigned int pages = DIV_ROUND_UP(height, 8);
    421	struct drm_device *drm = &ssd130x->drm;
    422	u32 array_idx = 0;
    423	int ret, i, j, k;
    424	u8 *data_array = NULL;
    425
    426	drm_WARN_ONCE(drm, y % 8 != 0, "y must be aligned to screen page\n");
    427
    428	data_array = kcalloc(width, pages, GFP_KERNEL);
    429	if (!data_array)
    430		return -ENOMEM;
    431
    432	/*
    433	 * The screen is divided in pages, each having a height of 8
    434	 * pixels, and the width of the screen. When sending a byte of
    435	 * data to the controller, it gives the 8 bits for the current
    436	 * column. I.e, the first byte are the 8 bits of the first
    437	 * column, then the 8 bits for the second column, etc.
    438	 *
    439	 *
    440	 * Representation of the screen, assuming it is 5 bits
    441	 * wide. Each letter-number combination is a bit that controls
    442	 * one pixel.
    443	 *
    444	 * A0 A1 A2 A3 A4
    445	 * B0 B1 B2 B3 B4
    446	 * C0 C1 C2 C3 C4
    447	 * D0 D1 D2 D3 D4
    448	 * E0 E1 E2 E3 E4
    449	 * F0 F1 F2 F3 F4
    450	 * G0 G1 G2 G3 G4
    451	 * H0 H1 H2 H3 H4
    452	 *
    453	 * If you want to update this screen, you need to send 5 bytes:
    454	 *  (1) A0 B0 C0 D0 E0 F0 G0 H0
    455	 *  (2) A1 B1 C1 D1 E1 F1 G1 H1
    456	 *  (3) A2 B2 C2 D2 E2 F2 G2 H2
    457	 *  (4) A3 B3 C3 D3 E3 F3 G3 H3
    458	 *  (5) A4 B4 C4 D4 E4 F4 G4 H4
    459	 */
    460
    461	if (!ssd130x->page_address_mode) {
    462		/* Set address range for horizontal addressing mode */
    463		ret = ssd130x_set_col_range(ssd130x, ssd130x->col_offset + x, width);
    464		if (ret < 0)
    465			goto out_free;
    466
    467		ret = ssd130x_set_page_range(ssd130x, ssd130x->page_offset + y / 8, pages);
    468		if (ret < 0)
    469			goto out_free;
    470	}
    471
    472	for (i = 0; i < pages; i++) {
    473		int m = 8;
    474
    475		/* Last page may be partial */
    476		if (8 * (y / 8 + i + 1) > ssd130x->height)
    477			m = ssd130x->height % 8;
    478		for (j = 0; j < width; j++) {
    479			u8 data = 0;
    480
    481			for (k = 0; k < m; k++) {
    482				u8 byte = buf[(8 * i + k) * line_length + j / 8];
    483				u8 bit = (byte >> (j % 8)) & 1;
    484
    485				data |= bit << k;
    486			}
    487			data_array[array_idx++] = data;
    488		}
    489
    490		/*
    491		 * In page addressing mode, the start address needs to be reset,
    492		 * and each page then needs to be written out separately.
    493		 */
    494		if (ssd130x->page_address_mode) {
    495			ret = ssd130x_set_page_pos(ssd130x,
    496						   ssd130x->page_offset + i,
    497						   ssd130x->col_offset + x);
    498			if (ret < 0)
    499				goto out_free;
    500
    501			ret = ssd130x_write_data(ssd130x, data_array, width);
    502			if (ret < 0)
    503				goto out_free;
    504
    505			array_idx = 0;
    506		}
    507	}
    508
    509	/* Write out update in one go if we aren't using page addressing mode */
    510	if (!ssd130x->page_address_mode)
    511		ret = ssd130x_write_data(ssd130x, data_array, width * pages);
    512
    513out_free:
    514	kfree(data_array);
    515	return ret;
    516}
    517
    518static void ssd130x_clear_screen(struct ssd130x_device *ssd130x)
    519{
    520	u8 *buf = NULL;
    521	struct drm_rect fullscreen = {
    522		.x1 = 0,
    523		.x2 = ssd130x->width,
    524		.y1 = 0,
    525		.y2 = ssd130x->height,
    526	};
    527
    528	buf = kcalloc(DIV_ROUND_UP(ssd130x->width, 8), ssd130x->height,
    529		      GFP_KERNEL);
    530	if (!buf)
    531		return;
    532
    533	ssd130x_update_rect(ssd130x, buf, &fullscreen);
    534
    535	kfree(buf);
    536}
    537
    538static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb, const struct iosys_map *map,
    539				struct drm_rect *rect)
    540{
    541	struct ssd130x_device *ssd130x = drm_to_ssd130x(fb->dev);
    542	void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */
    543	unsigned int dst_pitch;
    544	int ret = 0;
    545	u8 *buf = NULL;
    546
    547	/* Align y to display page boundaries */
    548	rect->y1 = round_down(rect->y1, 8);
    549	rect->y2 = min_t(unsigned int, round_up(rect->y2, 8), ssd130x->height);
    550
    551	dst_pitch = DIV_ROUND_UP(drm_rect_width(rect), 8);
    552	buf = kcalloc(dst_pitch, drm_rect_height(rect), GFP_KERNEL);
    553	if (!buf)
    554		return -ENOMEM;
    555
    556	drm_fb_xrgb8888_to_mono(buf, dst_pitch, vmap, fb, rect);
    557
    558	ssd130x_update_rect(ssd130x, buf, rect);
    559
    560	kfree(buf);
    561
    562	return ret;
    563}
    564
    565static int ssd130x_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
    566					   const struct drm_display_mode *mode)
    567{
    568	struct ssd130x_device *ssd130x = drm_to_ssd130x(pipe->crtc.dev);
    569
    570	if (mode->hdisplay != ssd130x->mode.hdisplay &&
    571	    mode->vdisplay != ssd130x->mode.vdisplay)
    572		return MODE_ONE_SIZE;
    573
    574	if (mode->hdisplay != ssd130x->mode.hdisplay)
    575		return MODE_ONE_WIDTH;
    576
    577	if (mode->vdisplay != ssd130x->mode.vdisplay)
    578		return MODE_ONE_HEIGHT;
    579
    580	return MODE_OK;
    581}
    582
    583static void ssd130x_display_pipe_enable(struct drm_simple_display_pipe *pipe,
    584					struct drm_crtc_state *crtc_state,
    585					struct drm_plane_state *plane_state)
    586{
    587	struct ssd130x_device *ssd130x = drm_to_ssd130x(pipe->crtc.dev);
    588	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
    589	struct drm_device *drm = &ssd130x->drm;
    590	int idx, ret;
    591
    592	ret = ssd130x_power_on(ssd130x);
    593	if (ret)
    594		return;
    595
    596	ret = ssd130x_init(ssd130x);
    597	if (ret)
    598		goto out_power_off;
    599
    600	if (!drm_dev_enter(drm, &idx))
    601		goto out_power_off;
    602
    603	ssd130x_fb_blit_rect(plane_state->fb, &shadow_plane_state->data[0], &plane_state->dst);
    604
    605	ssd130x_write_cmd(ssd130x, 1, SSD130X_DISPLAY_ON);
    606
    607	backlight_enable(ssd130x->bl_dev);
    608
    609	drm_dev_exit(idx);
    610
    611	return;
    612out_power_off:
    613	ssd130x_power_off(ssd130x);
    614}
    615
    616static void ssd130x_display_pipe_disable(struct drm_simple_display_pipe *pipe)
    617{
    618	struct ssd130x_device *ssd130x = drm_to_ssd130x(pipe->crtc.dev);
    619	struct drm_device *drm = &ssd130x->drm;
    620	int idx;
    621
    622	if (!drm_dev_enter(drm, &idx))
    623		return;
    624
    625	ssd130x_clear_screen(ssd130x);
    626
    627	backlight_disable(ssd130x->bl_dev);
    628
    629	ssd130x_write_cmd(ssd130x, 1, SSD130X_DISPLAY_OFF);
    630
    631	ssd130x_power_off(ssd130x);
    632
    633	drm_dev_exit(idx);
    634}
    635
    636static void ssd130x_display_pipe_update(struct drm_simple_display_pipe *pipe,
    637					struct drm_plane_state *old_plane_state)
    638{
    639	struct ssd130x_device *ssd130x = drm_to_ssd130x(pipe->crtc.dev);
    640	struct drm_plane_state *plane_state = pipe->plane.state;
    641	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
    642	struct drm_framebuffer *fb = plane_state->fb;
    643	struct drm_device *drm = &ssd130x->drm;
    644	struct drm_rect src_clip, dst_clip;
    645	int idx;
    646
    647	if (!fb)
    648		return;
    649
    650	if (!pipe->crtc.state->active)
    651		return;
    652
    653	if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &src_clip))
    654		return;
    655
    656	dst_clip = plane_state->dst;
    657	if (!drm_rect_intersect(&dst_clip, &src_clip))
    658		return;
    659
    660	if (!drm_dev_enter(drm, &idx))
    661		return;
    662
    663	ssd130x_fb_blit_rect(plane_state->fb, &shadow_plane_state->data[0], &dst_clip);
    664
    665	drm_dev_exit(idx);
    666}
    667
    668static const struct drm_simple_display_pipe_funcs ssd130x_pipe_funcs = {
    669	.mode_valid = ssd130x_display_pipe_mode_valid,
    670	.enable = ssd130x_display_pipe_enable,
    671	.disable = ssd130x_display_pipe_disable,
    672	.update = ssd130x_display_pipe_update,
    673	DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS,
    674};
    675
    676static int ssd130x_connector_get_modes(struct drm_connector *connector)
    677{
    678	struct ssd130x_device *ssd130x = drm_to_ssd130x(connector->dev);
    679	struct drm_display_mode *mode;
    680	struct device *dev = ssd130x->dev;
    681
    682	mode = drm_mode_duplicate(connector->dev, &ssd130x->mode);
    683	if (!mode) {
    684		dev_err(dev, "Failed to duplicated mode\n");
    685		return 0;
    686	}
    687
    688	drm_mode_probed_add(connector, mode);
    689	drm_set_preferred_mode(connector, mode->hdisplay, mode->vdisplay);
    690
    691	/* There is only a single mode */
    692	return 1;
    693}
    694
    695static const struct drm_connector_helper_funcs ssd130x_connector_helper_funcs = {
    696	.get_modes = ssd130x_connector_get_modes,
    697};
    698
    699static const struct drm_connector_funcs ssd130x_connector_funcs = {
    700	.reset = drm_atomic_helper_connector_reset,
    701	.fill_modes = drm_helper_probe_single_connector_modes,
    702	.destroy = drm_connector_cleanup,
    703	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
    704	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
    705};
    706
    707static const struct drm_mode_config_funcs ssd130x_mode_config_funcs = {
    708	.fb_create = drm_gem_fb_create_with_dirty,
    709	.atomic_check = drm_atomic_helper_check,
    710	.atomic_commit = drm_atomic_helper_commit,
    711};
    712
    713static const uint32_t ssd130x_formats[] = {
    714	DRM_FORMAT_XRGB8888,
    715};
    716
    717DEFINE_DRM_GEM_FOPS(ssd130x_fops);
    718
    719static const struct drm_driver ssd130x_drm_driver = {
    720	DRM_GEM_SHMEM_DRIVER_OPS,
    721	.name			= DRIVER_NAME,
    722	.desc			= DRIVER_DESC,
    723	.date			= DRIVER_DATE,
    724	.major			= DRIVER_MAJOR,
    725	.minor			= DRIVER_MINOR,
    726	.driver_features	= DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
    727	.fops			= &ssd130x_fops,
    728};
    729
    730static int ssd130x_update_bl(struct backlight_device *bdev)
    731{
    732	struct ssd130x_device *ssd130x = bl_get_data(bdev);
    733	int brightness = backlight_get_brightness(bdev);
    734	int ret;
    735
    736	ssd130x->contrast = brightness;
    737
    738	ret = ssd130x_write_cmd(ssd130x, 1, SSD130X_CONTRAST);
    739	if (ret < 0)
    740		return ret;
    741
    742	ret = ssd130x_write_cmd(ssd130x, 1, ssd130x->contrast);
    743	if (ret < 0)
    744		return ret;
    745
    746	return 0;
    747}
    748
    749static const struct backlight_ops ssd130xfb_bl_ops = {
    750	.update_status	= ssd130x_update_bl,
    751};
    752
    753static void ssd130x_parse_properties(struct ssd130x_device *ssd130x)
    754{
    755	struct device *dev = ssd130x->dev;
    756
    757	if (device_property_read_u32(dev, "solomon,width", &ssd130x->width))
    758		ssd130x->width = 96;
    759
    760	if (device_property_read_u32(dev, "solomon,height", &ssd130x->height))
    761		ssd130x->height = 16;
    762
    763	if (device_property_read_u32(dev, "solomon,page-offset", &ssd130x->page_offset))
    764		ssd130x->page_offset = 1;
    765
    766	if (device_property_read_u32(dev, "solomon,col-offset", &ssd130x->col_offset))
    767		ssd130x->col_offset = 0;
    768
    769	if (device_property_read_u32(dev, "solomon,com-offset", &ssd130x->com_offset))
    770		ssd130x->com_offset = 0;
    771
    772	if (device_property_read_u32(dev, "solomon,prechargep1", &ssd130x->prechargep1))
    773		ssd130x->prechargep1 = 2;
    774
    775	if (device_property_read_u32(dev, "solomon,prechargep2", &ssd130x->prechargep2))
    776		ssd130x->prechargep2 = 2;
    777
    778	if (!device_property_read_u8_array(dev, "solomon,lookup-table",
    779					   ssd130x->lookup_table,
    780					   ARRAY_SIZE(ssd130x->lookup_table)))
    781		ssd130x->lookup_table_set = 1;
    782
    783	ssd130x->seg_remap = !device_property_read_bool(dev, "solomon,segment-no-remap");
    784	ssd130x->com_seq = device_property_read_bool(dev, "solomon,com-seq");
    785	ssd130x->com_lrremap = device_property_read_bool(dev, "solomon,com-lrremap");
    786	ssd130x->com_invdir = device_property_read_bool(dev, "solomon,com-invdir");
    787	ssd130x->area_color_enable =
    788		device_property_read_bool(dev, "solomon,area-color-enable");
    789	ssd130x->low_power = device_property_read_bool(dev, "solomon,low-power");
    790
    791	ssd130x->contrast = 127;
    792	ssd130x->vcomh = ssd130x->device_info->default_vcomh;
    793
    794	/* Setup display timing */
    795	if (device_property_read_u32(dev, "solomon,dclk-div", &ssd130x->dclk_div))
    796		ssd130x->dclk_div = ssd130x->device_info->default_dclk_div;
    797	if (device_property_read_u32(dev, "solomon,dclk-frq", &ssd130x->dclk_frq))
    798		ssd130x->dclk_frq = ssd130x->device_info->default_dclk_frq;
    799}
    800
    801static int ssd130x_init_modeset(struct ssd130x_device *ssd130x)
    802{
    803	struct drm_display_mode *mode = &ssd130x->mode;
    804	struct device *dev = ssd130x->dev;
    805	struct drm_device *drm = &ssd130x->drm;
    806	unsigned long max_width, max_height;
    807	int ret;
    808
    809	ret = drmm_mode_config_init(drm);
    810	if (ret) {
    811		dev_err(dev, "DRM mode config init failed: %d\n", ret);
    812		return ret;
    813	}
    814
    815	mode->type = DRM_MODE_TYPE_DRIVER;
    816	mode->clock = 1;
    817	mode->hdisplay = mode->htotal = ssd130x->width;
    818	mode->hsync_start = mode->hsync_end = ssd130x->width;
    819	mode->vdisplay = mode->vtotal = ssd130x->height;
    820	mode->vsync_start = mode->vsync_end = ssd130x->height;
    821	mode->width_mm = 27;
    822	mode->height_mm = 27;
    823
    824	max_width = max_t(unsigned long, mode->hdisplay, DRM_SHADOW_PLANE_MAX_WIDTH);
    825	max_height = max_t(unsigned long, mode->vdisplay, DRM_SHADOW_PLANE_MAX_HEIGHT);
    826
    827	drm->mode_config.min_width = mode->hdisplay;
    828	drm->mode_config.max_width = max_width;
    829	drm->mode_config.min_height = mode->vdisplay;
    830	drm->mode_config.max_height = max_height;
    831	drm->mode_config.preferred_depth = 32;
    832	drm->mode_config.funcs = &ssd130x_mode_config_funcs;
    833
    834	ret = drm_connector_init(drm, &ssd130x->connector, &ssd130x_connector_funcs,
    835				 DRM_MODE_CONNECTOR_Unknown);
    836	if (ret) {
    837		dev_err(dev, "DRM connector init failed: %d\n", ret);
    838		return ret;
    839	}
    840
    841	drm_connector_helper_add(&ssd130x->connector, &ssd130x_connector_helper_funcs);
    842
    843	ret = drm_simple_display_pipe_init(drm, &ssd130x->pipe, &ssd130x_pipe_funcs,
    844					   ssd130x_formats, ARRAY_SIZE(ssd130x_formats),
    845					   NULL, &ssd130x->connector);
    846	if (ret) {
    847		dev_err(dev, "DRM simple display pipeline init failed: %d\n", ret);
    848		return ret;
    849	}
    850
    851	drm_plane_enable_fb_damage_clips(&ssd130x->pipe.plane);
    852
    853	drm_mode_config_reset(drm);
    854
    855	return 0;
    856}
    857
    858static int ssd130x_get_resources(struct ssd130x_device *ssd130x)
    859{
    860	struct device *dev = ssd130x->dev;
    861
    862	ssd130x->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
    863	if (IS_ERR(ssd130x->reset))
    864		return dev_err_probe(dev, PTR_ERR(ssd130x->reset),
    865				     "Failed to get reset gpio\n");
    866
    867	ssd130x->vcc_reg = devm_regulator_get(dev, "vcc");
    868	if (IS_ERR(ssd130x->vcc_reg))
    869		return dev_err_probe(dev, PTR_ERR(ssd130x->vcc_reg),
    870				     "Failed to get VCC regulator\n");
    871
    872	return 0;
    873}
    874
    875struct ssd130x_device *ssd130x_probe(struct device *dev, struct regmap *regmap)
    876{
    877	struct ssd130x_device *ssd130x;
    878	struct backlight_device *bl;
    879	struct drm_device *drm;
    880	int ret;
    881
    882	ssd130x = devm_drm_dev_alloc(dev, &ssd130x_drm_driver,
    883				     struct ssd130x_device, drm);
    884	if (IS_ERR(ssd130x))
    885		return ERR_PTR(dev_err_probe(dev, PTR_ERR(ssd130x),
    886					     "Failed to allocate DRM device\n"));
    887
    888	drm = &ssd130x->drm;
    889
    890	ssd130x->dev = dev;
    891	ssd130x->regmap = regmap;
    892	ssd130x->device_info = device_get_match_data(dev);
    893
    894	if (ssd130x->device_info->page_mode_only)
    895		ssd130x->page_address_mode = 1;
    896
    897	ssd130x_parse_properties(ssd130x);
    898
    899	ret = ssd130x_get_resources(ssd130x);
    900	if (ret)
    901		return ERR_PTR(ret);
    902
    903	bl = devm_backlight_device_register(dev, dev_name(dev), dev, ssd130x,
    904					    &ssd130xfb_bl_ops, NULL);
    905	if (IS_ERR(bl))
    906		return ERR_PTR(dev_err_probe(dev, PTR_ERR(bl),
    907					     "Unable to register backlight device\n"));
    908
    909	bl->props.brightness = ssd130x->contrast;
    910	bl->props.max_brightness = MAX_CONTRAST;
    911	ssd130x->bl_dev = bl;
    912
    913	ret = ssd130x_init_modeset(ssd130x);
    914	if (ret)
    915		return ERR_PTR(ret);
    916
    917	ret = drm_dev_register(drm, 0);
    918	if (ret)
    919		return ERR_PTR(dev_err_probe(dev, ret, "DRM device register failed\n"));
    920
    921	drm_fbdev_generic_setup(drm, 0);
    922
    923	return ssd130x;
    924}
    925EXPORT_SYMBOL_GPL(ssd130x_probe);
    926
    927void ssd130x_remove(struct ssd130x_device *ssd130x)
    928{
    929	drm_dev_unplug(&ssd130x->drm);
    930}
    931EXPORT_SYMBOL_GPL(ssd130x_remove);
    932
    933void ssd130x_shutdown(struct ssd130x_device *ssd130x)
    934{
    935	drm_atomic_helper_shutdown(&ssd130x->drm);
    936}
    937EXPORT_SYMBOL_GPL(ssd130x_shutdown);
    938
    939MODULE_DESCRIPTION(DRIVER_DESC);
    940MODULE_AUTHOR("Javier Martinez Canillas <javierm@redhat.com>");
    941MODULE_LICENSE("GPL v2");