brintos

brintos / linux-shallow public Read only

0
0
Text · 57.5 KiB · 6f51bcf Raw
2054 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * DRM driver for Solomon SSD13xx OLED displays4 *5 * Copyright 2022 Red Hat Inc.6 * Author: Javier Martinez Canillas <javierm@redhat.com>7 *8 * Based on drivers/video/fbdev/ssd1307fb.c9 * Copyright 2012 Free Electrons10 */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.h>22#include <drm/drm_atomic_helper.h>23#include <drm/drm_crtc_helper.h>24#include <drm/drm_damage_helper.h>25#include <drm/drm_edid.h>26#include <drm/drm_fbdev_shmem.h>27#include <drm/drm_format_helper.h>28#include <drm/drm_framebuffer.h>29#include <drm/drm_gem_atomic_helper.h>30#include <drm/drm_gem_framebuffer_helper.h>31#include <drm/drm_gem_shmem_helper.h>32#include <drm/drm_managed.h>33#include <drm/drm_modes.h>34#include <drm/drm_rect.h>35#include <drm/drm_probe_helper.h>36 37#include "ssd130x.h"38 39#define DRIVER_NAME	"ssd130x"40#define DRIVER_DESC	"DRM driver for Solomon SSD13xx OLED displays"41#define DRIVER_DATE	"20220131"42#define DRIVER_MAJOR	143#define DRIVER_MINOR	044 45#define SSD130X_PAGE_HEIGHT 846 47#define SSD132X_SEGMENT_WIDTH 248 49/* ssd13xx commands */50#define SSD13XX_CONTRAST			0x8151#define SSD13XX_SET_SEG_REMAP			0xa052#define SSD13XX_SET_MULTIPLEX_RATIO		0xa853#define SSD13XX_DISPLAY_OFF			0xae54#define SSD13XX_DISPLAY_ON			0xaf55 56#define SSD13XX_SET_SEG_REMAP_MASK		GENMASK(0, 0)57#define SSD13XX_SET_SEG_REMAP_SET(val)		FIELD_PREP(SSD13XX_SET_SEG_REMAP_MASK, (val))58 59/* ssd130x commands */60#define SSD130X_PAGE_COL_START_LOW		0x0061#define SSD130X_PAGE_COL_START_HIGH		0x1062#define SSD130X_SET_ADDRESS_MODE		0x2063#define SSD130X_SET_COL_RANGE			0x2164#define SSD130X_SET_PAGE_RANGE			0x2265#define SSD130X_SET_LOOKUP_TABLE		0x9166#define SSD130X_CHARGE_PUMP			0x8d67#define SSD130X_START_PAGE_ADDRESS		0xb068#define SSD130X_SET_COM_SCAN_DIR		0xc069#define SSD130X_SET_DISPLAY_OFFSET		0xd370#define SSD130X_SET_CLOCK_FREQ			0xd571#define SSD130X_SET_AREA_COLOR_MODE		0xd872#define SSD130X_SET_PRECHARGE_PERIOD		0xd973#define SSD130X_SET_COM_PINS_CONFIG		0xda74#define SSD130X_SET_VCOMH			0xdb75 76/* ssd130x commands accessors */77#define SSD130X_PAGE_COL_START_MASK		GENMASK(3, 0)78#define SSD130X_PAGE_COL_START_HIGH_SET(val)	FIELD_PREP(SSD130X_PAGE_COL_START_MASK, (val) >> 4)79#define SSD130X_PAGE_COL_START_LOW_SET(val)	FIELD_PREP(SSD130X_PAGE_COL_START_MASK, (val))80#define SSD130X_START_PAGE_ADDRESS_MASK		GENMASK(2, 0)81#define SSD130X_START_PAGE_ADDRESS_SET(val)	FIELD_PREP(SSD130X_START_PAGE_ADDRESS_MASK, (val))82#define SSD130X_SET_COM_SCAN_DIR_MASK		GENMASK(3, 3)83#define SSD130X_SET_COM_SCAN_DIR_SET(val)	FIELD_PREP(SSD130X_SET_COM_SCAN_DIR_MASK, (val))84#define SSD130X_SET_CLOCK_DIV_MASK		GENMASK(3, 0)85#define SSD130X_SET_CLOCK_DIV_SET(val)		FIELD_PREP(SSD130X_SET_CLOCK_DIV_MASK, (val))86#define SSD130X_SET_CLOCK_FREQ_MASK		GENMASK(7, 4)87#define SSD130X_SET_CLOCK_FREQ_SET(val)		FIELD_PREP(SSD130X_SET_CLOCK_FREQ_MASK, (val))88#define SSD130X_SET_PRECHARGE_PERIOD1_MASK	GENMASK(3, 0)89#define SSD130X_SET_PRECHARGE_PERIOD1_SET(val)	FIELD_PREP(SSD130X_SET_PRECHARGE_PERIOD1_MASK, (val))90#define SSD130X_SET_PRECHARGE_PERIOD2_MASK	GENMASK(7, 4)91#define SSD130X_SET_PRECHARGE_PERIOD2_SET(val)	FIELD_PREP(SSD130X_SET_PRECHARGE_PERIOD2_MASK, (val))92#define SSD130X_SET_COM_PINS_CONFIG1_MASK	GENMASK(4, 4)93#define SSD130X_SET_COM_PINS_CONFIG1_SET(val)	FIELD_PREP(SSD130X_SET_COM_PINS_CONFIG1_MASK, (val))94#define SSD130X_SET_COM_PINS_CONFIG2_MASK	GENMASK(5, 5)95#define SSD130X_SET_COM_PINS_CONFIG2_SET(val)	FIELD_PREP(SSD130X_SET_COM_PINS_CONFIG2_MASK, (val))96 97#define SSD130X_SET_ADDRESS_MODE_HORIZONTAL	0x0098#define SSD130X_SET_ADDRESS_MODE_VERTICAL	0x0199#define SSD130X_SET_ADDRESS_MODE_PAGE		0x02100 101#define SSD130X_SET_AREA_COLOR_MODE_ENABLE	0x1e102#define SSD130X_SET_AREA_COLOR_MODE_LOW_POWER	0x05103 104/* ssd132x commands */105#define SSD132X_SET_COL_RANGE			0x15106#define SSD132X_SET_DEACTIVATE_SCROLL		0x2e107#define SSD132X_SET_ROW_RANGE			0x75108#define SSD132X_SET_DISPLAY_START		0xa1109#define SSD132X_SET_DISPLAY_OFFSET		0xa2110#define SSD132X_SET_DISPLAY_NORMAL		0xa4111#define SSD132X_SET_FUNCTION_SELECT_A		0xab112#define SSD132X_SET_PHASE_LENGTH		0xb1113#define SSD132X_SET_CLOCK_FREQ			0xb3114#define SSD132X_SET_GPIO			0xb5115#define SSD132X_SET_PRECHARGE_PERIOD		0xb6116#define SSD132X_SET_GRAY_SCALE_TABLE		0xb8117#define SSD132X_SELECT_DEFAULT_TABLE		0xb9118#define SSD132X_SET_PRECHARGE_VOLTAGE		0xbc119#define SSD130X_SET_VCOMH_VOLTAGE		0xbe120#define SSD132X_SET_FUNCTION_SELECT_B		0xd5121 122/* ssd133x commands */123#define SSD133X_SET_COL_RANGE			0x15124#define SSD133X_SET_ROW_RANGE			0x75125#define SSD133X_CONTRAST_A			0x81126#define SSD133X_CONTRAST_B			0x82127#define SSD133X_CONTRAST_C			0x83128#define SSD133X_SET_MASTER_CURRENT		0x87129#define SSD132X_SET_PRECHARGE_A			0x8a130#define SSD132X_SET_PRECHARGE_B			0x8b131#define SSD132X_SET_PRECHARGE_C			0x8c132#define SSD133X_SET_DISPLAY_START		0xa1133#define SSD133X_SET_DISPLAY_OFFSET		0xa2134#define SSD133X_SET_DISPLAY_NORMAL		0xa4135#define SSD133X_SET_MASTER_CONFIG		0xad136#define SSD133X_POWER_SAVE_MODE			0xb0137#define SSD133X_PHASES_PERIOD			0xb1138#define SSD133X_SET_CLOCK_FREQ			0xb3139#define SSD133X_SET_PRECHARGE_VOLTAGE		0xbb140#define SSD133X_SET_VCOMH_VOLTAGE		0xbe141 142#define MAX_CONTRAST 255143 144const struct ssd130x_deviceinfo ssd130x_variants[] = {145	[SH1106_ID] = {146		.default_vcomh = 0x40,147		.default_dclk_div = 1,148		.default_dclk_frq = 5,149		.default_width = 132,150		.default_height = 64,151		.page_mode_only = 1,152		.family_id = SSD130X_FAMILY,153	},154	[SSD1305_ID] = {155		.default_vcomh = 0x34,156		.default_dclk_div = 1,157		.default_dclk_frq = 7,158		.default_width = 132,159		.default_height = 64,160		.family_id = SSD130X_FAMILY,161	},162	[SSD1306_ID] = {163		.default_vcomh = 0x20,164		.default_dclk_div = 1,165		.default_dclk_frq = 8,166		.need_chargepump = 1,167		.default_width = 128,168		.default_height = 64,169		.family_id = SSD130X_FAMILY,170	},171	[SSD1307_ID] = {172		.default_vcomh = 0x20,173		.default_dclk_div = 2,174		.default_dclk_frq = 12,175		.need_pwm = 1,176		.default_width = 128,177		.default_height = 39,178		.family_id = SSD130X_FAMILY,179	},180	[SSD1309_ID] = {181		.default_vcomh = 0x34,182		.default_dclk_div = 1,183		.default_dclk_frq = 10,184		.default_width = 128,185		.default_height = 64,186		.family_id = SSD130X_FAMILY,187	},188	/* ssd132x family */189	[SSD1322_ID] = {190		.default_width = 480,191		.default_height = 128,192		.family_id = SSD132X_FAMILY,193	},194	[SSD1325_ID] = {195		.default_width = 128,196		.default_height = 80,197		.family_id = SSD132X_FAMILY,198	},199	[SSD1327_ID] = {200		.default_width = 128,201		.default_height = 128,202		.family_id = SSD132X_FAMILY,203	},204	/* ssd133x family */205	[SSD1331_ID] = {206		.default_width = 96,207		.default_height = 64,208		.family_id = SSD133X_FAMILY,209	}210};211EXPORT_SYMBOL_NS_GPL(ssd130x_variants, DRM_SSD130X);212 213struct ssd130x_crtc_state {214	struct drm_crtc_state base;215	/* Buffer to store pixels in HW format and written to the panel */216	u8 *data_array;217};218 219struct ssd130x_plane_state {220	struct drm_shadow_plane_state base;221	/* Intermediate buffer to convert pixels from XRGB8888 to HW format */222	u8 *buffer;223};224 225static inline struct ssd130x_crtc_state *to_ssd130x_crtc_state(struct drm_crtc_state *state)226{227	return container_of(state, struct ssd130x_crtc_state, base);228}229 230static inline struct ssd130x_plane_state *to_ssd130x_plane_state(struct drm_plane_state *state)231{232	return container_of(state, struct ssd130x_plane_state, base.base);233}234 235static inline struct ssd130x_device *drm_to_ssd130x(struct drm_device *drm)236{237	return container_of(drm, struct ssd130x_device, drm);238}239 240/*241 * Helper to write data (SSD13XX_DATA) to the device.242 */243static int ssd130x_write_data(struct ssd130x_device *ssd130x, u8 *values, int count)244{245	return regmap_bulk_write(ssd130x->regmap, SSD13XX_DATA, values, count);246}247 248/*249 * Helper to write command (SSD13XX_COMMAND). The fist variadic argument250 * is the command to write and the following are the command options.251 *252 * Note that the ssd13xx protocol requires each command and option to be253 * written as a SSD13XX_COMMAND device register value. That is why a call254 * to regmap_write(..., SSD13XX_COMMAND, ...) is done for each argument.255 */256static int ssd130x_write_cmd(struct ssd130x_device *ssd130x, int count,257			     /* u8 cmd, u8 option, ... */...)258{259	va_list ap;260	u8 value;261	int ret;262 263	va_start(ap, count);264 265	do {266		value = va_arg(ap, int);267		ret = regmap_write(ssd130x->regmap, SSD13XX_COMMAND, value);268		if (ret)269			goto out_end;270	} while (--count);271 272out_end:273	va_end(ap);274 275	return ret;276}277 278/* Set address range for horizontal/vertical addressing modes */279static int ssd130x_set_col_range(struct ssd130x_device *ssd130x,280				 u8 col_start, u8 cols)281{282	u8 col_end = col_start + cols - 1;283	int ret;284 285	if (col_start == ssd130x->col_start && col_end == ssd130x->col_end)286		return 0;287 288	ret = ssd130x_write_cmd(ssd130x, 3, SSD130X_SET_COL_RANGE, col_start, col_end);289	if (ret < 0)290		return ret;291 292	ssd130x->col_start = col_start;293	ssd130x->col_end = col_end;294	return 0;295}296 297static int ssd130x_set_page_range(struct ssd130x_device *ssd130x,298				  u8 page_start, u8 pages)299{300	u8 page_end = page_start + pages - 1;301	int ret;302 303	if (page_start == ssd130x->page_start && page_end == ssd130x->page_end)304		return 0;305 306	ret = ssd130x_write_cmd(ssd130x, 3, SSD130X_SET_PAGE_RANGE, page_start, page_end);307	if (ret < 0)308		return ret;309 310	ssd130x->page_start = page_start;311	ssd130x->page_end = page_end;312	return 0;313}314 315/* Set page and column start address for page addressing mode */316static int ssd130x_set_page_pos(struct ssd130x_device *ssd130x,317				u8 page_start, u8 col_start)318{319	int ret;320	u32 page, col_low, col_high;321 322	page = SSD130X_START_PAGE_ADDRESS |323	       SSD130X_START_PAGE_ADDRESS_SET(page_start);324	col_low = SSD130X_PAGE_COL_START_LOW |325		  SSD130X_PAGE_COL_START_LOW_SET(col_start);326	col_high = SSD130X_PAGE_COL_START_HIGH |327		   SSD130X_PAGE_COL_START_HIGH_SET(col_start);328	ret = ssd130x_write_cmd(ssd130x, 3, page, col_low, col_high);329	if (ret < 0)330		return ret;331 332	return 0;333}334 335static int ssd130x_pwm_enable(struct ssd130x_device *ssd130x)336{337	struct device *dev = ssd130x->dev;338	struct pwm_state pwmstate;339 340	ssd130x->pwm = pwm_get(dev, NULL);341	if (IS_ERR(ssd130x->pwm)) {342		dev_err(dev, "Could not get PWM from firmware description!\n");343		return PTR_ERR(ssd130x->pwm);344	}345 346	pwm_init_state(ssd130x->pwm, &pwmstate);347	pwm_set_relative_duty_cycle(&pwmstate, 50, 100);348	pwm_apply_might_sleep(ssd130x->pwm, &pwmstate);349 350	/* Enable the PWM */351	pwm_enable(ssd130x->pwm);352 353	dev_dbg(dev, "Using PWM %s with a %lluns period.\n",354		ssd130x->pwm->label, pwm_get_period(ssd130x->pwm));355 356	return 0;357}358 359static void ssd130x_reset(struct ssd130x_device *ssd130x)360{361	if (!ssd130x->reset)362		return;363 364	/* Reset the screen */365	gpiod_set_value_cansleep(ssd130x->reset, 1);366	udelay(4);367	gpiod_set_value_cansleep(ssd130x->reset, 0);368	udelay(4);369}370 371static int ssd130x_power_on(struct ssd130x_device *ssd130x)372{373	struct device *dev = ssd130x->dev;374	int ret;375 376	ssd130x_reset(ssd130x);377 378	ret = regulator_enable(ssd130x->vcc_reg);379	if (ret) {380		dev_err(dev, "Failed to enable VCC: %d\n", ret);381		return ret;382	}383 384	if (ssd130x->device_info->need_pwm) {385		ret = ssd130x_pwm_enable(ssd130x);386		if (ret) {387			dev_err(dev, "Failed to enable PWM: %d\n", ret);388			regulator_disable(ssd130x->vcc_reg);389			return ret;390		}391	}392 393	return 0;394}395 396static void ssd130x_power_off(struct ssd130x_device *ssd130x)397{398	pwm_disable(ssd130x->pwm);399	pwm_put(ssd130x->pwm);400 401	regulator_disable(ssd130x->vcc_reg);402}403 404static int ssd130x_init(struct ssd130x_device *ssd130x)405{406	u32 precharge, dclk, com_invdir, compins, chargepump, seg_remap;407	bool scan_mode;408	int ret;409 410	/* Set initial contrast */411	ret = ssd130x_write_cmd(ssd130x, 2, SSD13XX_CONTRAST, ssd130x->contrast);412	if (ret < 0)413		return ret;414 415	/* Set segment re-map */416	seg_remap = (SSD13XX_SET_SEG_REMAP |417		     SSD13XX_SET_SEG_REMAP_SET(ssd130x->seg_remap));418	ret = ssd130x_write_cmd(ssd130x, 1, seg_remap);419	if (ret < 0)420		return ret;421 422	/* Set COM direction */423	com_invdir = (SSD130X_SET_COM_SCAN_DIR |424		      SSD130X_SET_COM_SCAN_DIR_SET(ssd130x->com_invdir));425	ret = ssd130x_write_cmd(ssd130x,  1, com_invdir);426	if (ret < 0)427		return ret;428 429	/* Set multiplex ratio value */430	ret = ssd130x_write_cmd(ssd130x, 2, SSD13XX_SET_MULTIPLEX_RATIO, ssd130x->height - 1);431	if (ret < 0)432		return ret;433 434	/* set display offset value */435	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_DISPLAY_OFFSET, ssd130x->com_offset);436	if (ret < 0)437		return ret;438 439	/* Set clock frequency */440	dclk = (SSD130X_SET_CLOCK_DIV_SET(ssd130x->dclk_div - 1) |441		SSD130X_SET_CLOCK_FREQ_SET(ssd130x->dclk_frq));442	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_CLOCK_FREQ, dclk);443	if (ret < 0)444		return ret;445 446	/* Set Area Color Mode ON/OFF & Low Power Display Mode */447	if (ssd130x->area_color_enable || ssd130x->low_power) {448		u32 mode = 0;449 450		if (ssd130x->area_color_enable)451			mode |= SSD130X_SET_AREA_COLOR_MODE_ENABLE;452 453		if (ssd130x->low_power)454			mode |= SSD130X_SET_AREA_COLOR_MODE_LOW_POWER;455 456		ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_AREA_COLOR_MODE, mode);457		if (ret < 0)458			return ret;459	}460 461	/* Set precharge period in number of ticks from the internal clock */462	precharge = (SSD130X_SET_PRECHARGE_PERIOD1_SET(ssd130x->prechargep1) |463		     SSD130X_SET_PRECHARGE_PERIOD2_SET(ssd130x->prechargep2));464	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_PRECHARGE_PERIOD, precharge);465	if (ret < 0)466		return ret;467 468	/* Set COM pins configuration */469	compins = BIT(1);470	/*471	 * The COM scan mode field values are the inverse of the boolean DT472	 * property "solomon,com-seq". The value 0b means scan from COM0 to473	 * COM[N - 1] while 1b means scan from COM[N - 1] to COM0.474	 */475	scan_mode = !ssd130x->com_seq;476	compins |= (SSD130X_SET_COM_PINS_CONFIG1_SET(scan_mode) |477		    SSD130X_SET_COM_PINS_CONFIG2_SET(ssd130x->com_lrremap));478	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_COM_PINS_CONFIG, compins);479	if (ret < 0)480		return ret;481 482	/* Set VCOMH */483	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_VCOMH, ssd130x->vcomh);484	if (ret < 0)485		return ret;486 487	/* Turn on the DC-DC Charge Pump */488	chargepump = BIT(4);489 490	if (ssd130x->device_info->need_chargepump)491		chargepump |= BIT(2);492 493	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_CHARGE_PUMP, chargepump);494	if (ret < 0)495		return ret;496 497	/* Set lookup table */498	if (ssd130x->lookup_table_set) {499		int i;500 501		ret = ssd130x_write_cmd(ssd130x, 1, SSD130X_SET_LOOKUP_TABLE);502		if (ret < 0)503			return ret;504 505		for (i = 0; i < ARRAY_SIZE(ssd130x->lookup_table); i++) {506			u8 val = ssd130x->lookup_table[i];507 508			if (val < 31 || val > 63)509				dev_warn(ssd130x->dev,510					 "lookup table index %d value out of range 31 <= %d <= 63\n",511					 i, val);512			ret = ssd130x_write_cmd(ssd130x, 1, val);513			if (ret < 0)514				return ret;515		}516	}517 518	/* Switch to page addressing mode */519	if (ssd130x->page_address_mode)520		return ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_ADDRESS_MODE,521					 SSD130X_SET_ADDRESS_MODE_PAGE);522 523	/* Switch to horizontal addressing mode */524	return ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_ADDRESS_MODE,525				 SSD130X_SET_ADDRESS_MODE_HORIZONTAL);526}527 528static int ssd132x_init(struct ssd130x_device *ssd130x)529{530	int ret;531 532	/* Set initial contrast */533	ret = ssd130x_write_cmd(ssd130x, 2, SSD13XX_CONTRAST, 0x80);534	if (ret < 0)535		return ret;536 537	/* Set column start and end */538	ret = ssd130x_write_cmd(ssd130x, 3, SSD132X_SET_COL_RANGE, 0x00,539				ssd130x->width / SSD132X_SEGMENT_WIDTH - 1);540	if (ret < 0)541		return ret;542 543	/* Set row start and end */544	ret = ssd130x_write_cmd(ssd130x, 3, SSD132X_SET_ROW_RANGE, 0x00, ssd130x->height - 1);545	if (ret < 0)546		return ret;547	/*548	 * Horizontal Address Increment549	 * Re-map for Column Address, Nibble and COM550	 * COM Split Odd Even551	 */552	ret = ssd130x_write_cmd(ssd130x, 2, SSD13XX_SET_SEG_REMAP, 0x53);553	if (ret < 0)554		return ret;555 556	/* Set display start and offset */557	ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_DISPLAY_START, 0x00);558	if (ret < 0)559		return ret;560 561	ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_DISPLAY_OFFSET, 0x00);562	if (ret < 0)563		return ret;564 565	/* Set display mode normal */566	ret = ssd130x_write_cmd(ssd130x, 1, SSD132X_SET_DISPLAY_NORMAL);567	if (ret < 0)568		return ret;569 570	/* Set multiplex ratio value */571	ret = ssd130x_write_cmd(ssd130x, 2, SSD13XX_SET_MULTIPLEX_RATIO, ssd130x->height - 1);572	if (ret < 0)573		return ret;574 575	/* Set phase length */576	ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_PHASE_LENGTH, 0x55);577	if (ret < 0)578		return ret;579 580	/* Select default linear gray scale table */581	ret = ssd130x_write_cmd(ssd130x, 1, SSD132X_SELECT_DEFAULT_TABLE);582	if (ret < 0)583		return ret;584 585	/* Set clock frequency */586	ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_CLOCK_FREQ, 0x01);587	if (ret < 0)588		return ret;589 590	/* Enable internal VDD regulator */591	ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_FUNCTION_SELECT_A, 0x1);592	if (ret < 0)593		return ret;594 595	/* Set pre-charge period */596	ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_PRECHARGE_PERIOD, 0x01);597	if (ret < 0)598		return ret;599 600	/* Set pre-charge voltage */601	ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_PRECHARGE_VOLTAGE, 0x08);602	if (ret < 0)603		return ret;604 605	/* Set VCOMH voltage */606	ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_VCOMH_VOLTAGE, 0x07);607	if (ret < 0)608		return ret;609 610	/* Enable second pre-charge and internal VSL */611	ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_FUNCTION_SELECT_B, 0x62);612	if (ret < 0)613		return ret;614 615	return 0;616}617 618static int ssd133x_init(struct ssd130x_device *ssd130x)619{620	int ret;621 622	/* Set color A contrast */623	ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_CONTRAST_A, 0x91);624	if (ret < 0)625		return ret;626 627	/* Set color B contrast */628	ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_CONTRAST_B, 0x50);629	if (ret < 0)630		return ret;631 632	/* Set color C contrast */633	ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_CONTRAST_C, 0x7d);634	if (ret < 0)635		return ret;636 637	/* Set master current */638	ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_MASTER_CURRENT, 0x06);639	if (ret < 0)640		return ret;641 642	/* Set column start and end */643	ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_COL_RANGE, 0x00, ssd130x->width - 1);644	if (ret < 0)645		return ret;646 647	/* Set row start and end */648	ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_ROW_RANGE, 0x00, ssd130x->height - 1);649	if (ret < 0)650		return ret;651 652	/*653	 * Horizontal Address Increment654	 * Normal order SA,SB,SC (e.g. RGB)655	 * COM Split Odd Even656	 * 256 color format657	 */658	ret = ssd130x_write_cmd(ssd130x, 2, SSD13XX_SET_SEG_REMAP, 0x20);659	if (ret < 0)660		return ret;661 662	/* Set display start and offset */663	ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_DISPLAY_START, 0x00);664	if (ret < 0)665		return ret;666 667	ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_DISPLAY_OFFSET, 0x00);668	if (ret < 0)669		return ret;670 671	/* Set display mode normal */672	ret = ssd130x_write_cmd(ssd130x, 1, SSD133X_SET_DISPLAY_NORMAL);673	if (ret < 0)674		return ret;675 676	/* Set multiplex ratio value */677	ret = ssd130x_write_cmd(ssd130x, 2, SSD13XX_SET_MULTIPLEX_RATIO, ssd130x->height - 1);678	if (ret < 0)679		return ret;680 681	/* Set master configuration */682	ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_MASTER_CONFIG, 0x8e);683	if (ret < 0)684		return ret;685 686	/* Set power mode */687	ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_POWER_SAVE_MODE, 0x0b);688	if (ret < 0)689		return ret;690 691	/* Set Phase 1 and 2 period */692	ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_PHASES_PERIOD, 0x31);693	if (ret < 0)694		return ret;695 696	/* Set clock divider */697	ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_CLOCK_FREQ, 0xf0);698	if (ret < 0)699		return ret;700 701	/* Set pre-charge A */702	ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_PRECHARGE_A, 0x64);703	if (ret < 0)704		return ret;705 706	/* Set pre-charge B */707	ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_PRECHARGE_B, 0x78);708	if (ret < 0)709		return ret;710 711	/* Set pre-charge C */712	ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_PRECHARGE_C, 0x64);713	if (ret < 0)714		return ret;715 716	/* Set pre-charge level */717	ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_PRECHARGE_VOLTAGE, 0x3a);718	if (ret < 0)719		return ret;720 721	/* Set VCOMH voltage */722	ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_VCOMH_VOLTAGE, 0x3e);723	if (ret < 0)724		return ret;725 726	return 0;727}728 729static int ssd130x_update_rect(struct ssd130x_device *ssd130x,730			       struct drm_rect *rect, u8 *buf,731			       u8 *data_array)732{733	unsigned int x = rect->x1;734	unsigned int y = rect->y1;735	unsigned int width = drm_rect_width(rect);736	unsigned int height = drm_rect_height(rect);737	unsigned int line_length = DIV_ROUND_UP(width, 8);738	unsigned int page_height = SSD130X_PAGE_HEIGHT;739	unsigned int pages = DIV_ROUND_UP(height, page_height);740	struct drm_device *drm = &ssd130x->drm;741	u32 array_idx = 0;742	int ret, i, j, k;743 744	drm_WARN_ONCE(drm, y % page_height != 0, "y must be aligned to screen page\n");745 746	/*747	 * The screen is divided in pages, each having a height of 8748	 * pixels, and the width of the screen. When sending a byte of749	 * data to the controller, it gives the 8 bits for the current750	 * column. I.e, the first byte are the 8 bits of the first751	 * column, then the 8 bits for the second column, etc.752	 *753	 *754	 * Representation of the screen, assuming it is 5 bits755	 * wide. Each letter-number combination is a bit that controls756	 * one pixel.757	 *758	 * A0 A1 A2 A3 A4759	 * B0 B1 B2 B3 B4760	 * C0 C1 C2 C3 C4761	 * D0 D1 D2 D3 D4762	 * E0 E1 E2 E3 E4763	 * F0 F1 F2 F3 F4764	 * G0 G1 G2 G3 G4765	 * H0 H1 H2 H3 H4766	 *767	 * If you want to update this screen, you need to send 5 bytes:768	 *  (1) A0 B0 C0 D0 E0 F0 G0 H0769	 *  (2) A1 B1 C1 D1 E1 F1 G1 H1770	 *  (3) A2 B2 C2 D2 E2 F2 G2 H2771	 *  (4) A3 B3 C3 D3 E3 F3 G3 H3772	 *  (5) A4 B4 C4 D4 E4 F4 G4 H4773	 */774 775	if (!ssd130x->page_address_mode) {776		u8 page_start;777 778		/* Set address range for horizontal addressing mode */779		ret = ssd130x_set_col_range(ssd130x, ssd130x->col_offset + x, width);780		if (ret < 0)781			return ret;782 783		page_start = ssd130x->page_offset + y / page_height;784		ret = ssd130x_set_page_range(ssd130x, page_start, pages);785		if (ret < 0)786			return ret;787	}788 789	for (i = 0; i < pages; i++) {790		int m = page_height;791 792		/* Last page may be partial */793		if (page_height * (y / page_height + i + 1) > ssd130x->height)794			m = ssd130x->height % page_height;795 796		for (j = 0; j < width; j++) {797			u8 data = 0;798 799			for (k = 0; k < m; k++) {800				u32 idx = (page_height * i + k) * line_length + j / 8;801				u8 byte = buf[idx];802				u8 bit = (byte >> (j % 8)) & 1;803 804				data |= bit << k;805			}806			data_array[array_idx++] = data;807		}808 809		/*810		 * In page addressing mode, the start address needs to be reset,811		 * and each page then needs to be written out separately.812		 */813		if (ssd130x->page_address_mode) {814			ret = ssd130x_set_page_pos(ssd130x,815						   ssd130x->page_offset + i,816						   ssd130x->col_offset + x);817			if (ret < 0)818				return ret;819 820			ret = ssd130x_write_data(ssd130x, data_array, width);821			if (ret < 0)822				return ret;823 824			array_idx = 0;825		}826	}827 828	/* Write out update in one go if we aren't using page addressing mode */829	if (!ssd130x->page_address_mode)830		ret = ssd130x_write_data(ssd130x, data_array, width * pages);831 832	return ret;833}834 835static int ssd132x_update_rect(struct ssd130x_device *ssd130x,836			       struct drm_rect *rect, u8 *buf,837			       u8 *data_array)838{839	unsigned int x = rect->x1;840	unsigned int y = rect->y1;841	unsigned int segment_width = SSD132X_SEGMENT_WIDTH;842	unsigned int width = drm_rect_width(rect);843	unsigned int height = drm_rect_height(rect);844	unsigned int columns = DIV_ROUND_UP(width, segment_width);845	unsigned int rows = height;846	struct drm_device *drm = &ssd130x->drm;847	u32 array_idx = 0;848	unsigned int i, j;849	int ret;850 851	drm_WARN_ONCE(drm, x % segment_width != 0, "x must be aligned to screen segment\n");852 853	/*854	 * The screen is divided in Segment and Common outputs, where855	 * COM0 to COM[N - 1] are the rows and SEG0 to SEG[M - 1] are856	 * the columns.857	 *858	 * Each Segment has a 4-bit pixel and each Common output has a859	 * row of pixels. When using the (default) horizontal address860	 * increment mode, each byte of data sent to the controller has861	 * two Segments (e.g: SEG0 and SEG1) that are stored in the lower862	 * and higher nibbles of a single byte representing one column.863	 * That is, the first byte are SEG0 (D0[3:0]) and SEG1 (D0[7:4]),864	 * the second byte are SEG2 (D1[3:0]) and SEG3 (D1[7:4]) and so on.865	 */866 867	/* Set column start and end */868	ret = ssd130x_write_cmd(ssd130x, 3, SSD132X_SET_COL_RANGE, x / segment_width, columns - 1);869	if (ret < 0)870		return ret;871 872	/* Set row start and end */873	ret = ssd130x_write_cmd(ssd130x, 3, SSD132X_SET_ROW_RANGE, y, rows - 1);874	if (ret < 0)875		return ret;876 877	for (i = 0; i < height; i++) {878		/* Process pair of pixels and combine them into a single byte */879		for (j = 0; j < width; j += segment_width) {880			u8 n1 = buf[i * width + j];881			u8 n2 = buf[i * width + j + 1];882 883			data_array[array_idx++] = (n2 << 4) | n1;884		}885	}886 887	/* Write out update in one go since horizontal addressing mode is used */888	ret = ssd130x_write_data(ssd130x, data_array, columns * rows);889 890	return ret;891}892 893static int ssd133x_update_rect(struct ssd130x_device *ssd130x,894			       struct drm_rect *rect, u8 *data_array,895			       unsigned int pitch)896{897	unsigned int x = rect->x1;898	unsigned int y = rect->y1;899	unsigned int columns = drm_rect_width(rect);900	unsigned int rows = drm_rect_height(rect);901	int ret;902 903	/*904	 * The screen is divided in Segment and Common outputs, where905	 * COM0 to COM[N - 1] are the rows and SEG0 to SEG[M - 1] are906	 * the columns.907	 *908	 * Each Segment has a 8-bit pixel and each Common output has a909	 * row of pixels. When using the (default) horizontal address910	 * increment mode, each byte of data sent to the controller has911	 * a Segment (e.g: SEG0).912	 *913	 * When using the 256 color depth format, each pixel contains 3914	 * sub-pixels for color A, B and C. These have 3 bit, 3 bit and915	 * 2 bits respectively.916	 */917 918	/* Set column start and end */919	ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_COL_RANGE, x, columns - 1);920	if (ret < 0)921		return ret;922 923	/* Set row start and end */924	ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_ROW_RANGE, y, rows - 1);925	if (ret < 0)926		return ret;927 928	/* Write out update in one go since horizontal addressing mode is used */929	ret = ssd130x_write_data(ssd130x, data_array, pitch * rows);930 931	return ret;932}933 934static void ssd130x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array)935{936	unsigned int pages = DIV_ROUND_UP(ssd130x->height, SSD130X_PAGE_HEIGHT);937	unsigned int width = ssd130x->width;938	int ret, i;939 940	if (!ssd130x->page_address_mode) {941		memset(data_array, 0, width * pages);942 943		/* Set address range for horizontal addressing mode */944		ret = ssd130x_set_col_range(ssd130x, ssd130x->col_offset, width);945		if (ret < 0)946			return;947 948		ret = ssd130x_set_page_range(ssd130x, ssd130x->page_offset, pages);949		if (ret < 0)950			return;951 952		/* Write out update in one go if we aren't using page addressing mode */953		ssd130x_write_data(ssd130x, data_array, width * pages);954	} else {955		/*956		 * In page addressing mode, the start address needs to be reset,957		 * and each page then needs to be written out separately.958		 */959		memset(data_array, 0, width);960 961		for (i = 0; i < pages; i++) {962			ret = ssd130x_set_page_pos(ssd130x,963						   ssd130x->page_offset + i,964						   ssd130x->col_offset);965			if (ret < 0)966				return;967 968			ret = ssd130x_write_data(ssd130x, data_array, width);969			if (ret < 0)970				return;971		}972	}973}974 975static void ssd132x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array)976{977	unsigned int columns = DIV_ROUND_UP(ssd130x->height, SSD132X_SEGMENT_WIDTH);978	unsigned int height = ssd130x->height;979 980	memset(data_array, 0, columns * height);981 982	/* Write out update in one go since horizontal addressing mode is used */983	ssd130x_write_data(ssd130x, data_array, columns * height);984}985 986static void ssd133x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array)987{988	const struct drm_format_info *fi = drm_format_info(DRM_FORMAT_RGB332);989	unsigned int pitch;990 991	if (!fi)992		return;993 994	pitch = drm_format_info_min_pitch(fi, 0, ssd130x->width);995 996	memset(data_array, 0, pitch * ssd130x->height);997 998	/* Write out update in one go since horizontal addressing mode is used */999	ssd130x_write_data(ssd130x, data_array, pitch * ssd130x->height);1000}1001 1002static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb,1003				const struct iosys_map *vmap,1004				struct drm_rect *rect,1005				u8 *buf, u8 *data_array,1006				struct drm_format_conv_state *fmtcnv_state)1007{1008	struct ssd130x_device *ssd130x = drm_to_ssd130x(fb->dev);1009	struct iosys_map dst;1010	unsigned int dst_pitch;1011	int ret = 0;1012 1013	/* Align y to display page boundaries */1014	rect->y1 = round_down(rect->y1, SSD130X_PAGE_HEIGHT);1015	rect->y2 = min_t(unsigned int, round_up(rect->y2, SSD130X_PAGE_HEIGHT), ssd130x->height);1016 1017	dst_pitch = DIV_ROUND_UP(drm_rect_width(rect), 8);1018 1019	ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);1020	if (ret)1021		return ret;1022 1023	iosys_map_set_vaddr(&dst, buf);1024	drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, vmap, fb, rect, fmtcnv_state);1025 1026	drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);1027 1028	ssd130x_update_rect(ssd130x, rect, buf, data_array);1029 1030	return ret;1031}1032 1033static int ssd132x_fb_blit_rect(struct drm_framebuffer *fb,1034				const struct iosys_map *vmap,1035				struct drm_rect *rect, u8 *buf,1036				u8 *data_array,1037				struct drm_format_conv_state *fmtcnv_state)1038{1039	struct ssd130x_device *ssd130x = drm_to_ssd130x(fb->dev);1040	unsigned int dst_pitch = drm_rect_width(rect);1041	struct iosys_map dst;1042	int ret = 0;1043 1044	/* Align x to display segment boundaries */1045	rect->x1 = round_down(rect->x1, SSD132X_SEGMENT_WIDTH);1046	rect->x2 = min_t(unsigned int, round_up(rect->x2, SSD132X_SEGMENT_WIDTH),1047			 ssd130x->width);1048 1049	ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);1050	if (ret)1051		return ret;1052 1053	iosys_map_set_vaddr(&dst, buf);1054	drm_fb_xrgb8888_to_gray8(&dst, &dst_pitch, vmap, fb, rect, fmtcnv_state);1055 1056	drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);1057 1058	ssd132x_update_rect(ssd130x, rect, buf, data_array);1059 1060	return ret;1061}1062 1063static int ssd133x_fb_blit_rect(struct drm_framebuffer *fb,1064				const struct iosys_map *vmap,1065				struct drm_rect *rect, u8 *data_array,1066				struct drm_format_conv_state *fmtcnv_state)1067{1068	struct ssd130x_device *ssd130x = drm_to_ssd130x(fb->dev);1069	const struct drm_format_info *fi = drm_format_info(DRM_FORMAT_RGB332);1070	unsigned int dst_pitch;1071	struct iosys_map dst;1072	int ret = 0;1073 1074	if (!fi)1075		return -EINVAL;1076 1077	dst_pitch = drm_format_info_min_pitch(fi, 0, drm_rect_width(rect));1078 1079	ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);1080	if (ret)1081		return ret;1082 1083	iosys_map_set_vaddr(&dst, data_array);1084	drm_fb_xrgb8888_to_rgb332(&dst, &dst_pitch, vmap, fb, rect, fmtcnv_state);1085 1086	drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);1087 1088	ssd133x_update_rect(ssd130x, rect, data_array, dst_pitch);1089 1090	return ret;1091}1092 1093static int ssd130x_primary_plane_atomic_check(struct drm_plane *plane,1094					      struct drm_atomic_state *state)1095{1096	struct drm_device *drm = plane->dev;1097	struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);1098	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);1099	struct ssd130x_plane_state *ssd130x_state = to_ssd130x_plane_state(plane_state);1100	struct drm_shadow_plane_state *shadow_plane_state = &ssd130x_state->base;1101	struct drm_crtc *crtc = plane_state->crtc;1102	struct drm_crtc_state *crtc_state = NULL;1103	const struct drm_format_info *fi;1104	unsigned int pitch;1105	int ret;1106 1107	if (crtc)1108		crtc_state = drm_atomic_get_new_crtc_state(state, crtc);1109 1110	ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,1111						  DRM_PLANE_NO_SCALING,1112						  DRM_PLANE_NO_SCALING,1113						  false, false);1114	if (ret)1115		return ret;1116	else if (!plane_state->visible)1117		return 0;1118 1119	fi = drm_format_info(DRM_FORMAT_R1);1120	if (!fi)1121		return -EINVAL;1122 1123	pitch = drm_format_info_min_pitch(fi, 0, ssd130x->width);1124 1125	if (plane_state->fb->format != fi) {1126		void *buf;1127 1128		/* format conversion necessary; reserve buffer */1129		buf = drm_format_conv_state_reserve(&shadow_plane_state->fmtcnv_state,1130						    pitch, GFP_KERNEL);1131		if (!buf)1132			return -ENOMEM;1133	}1134 1135	ssd130x_state->buffer = kcalloc(pitch, ssd130x->height, GFP_KERNEL);1136	if (!ssd130x_state->buffer)1137		return -ENOMEM;1138 1139	return 0;1140}1141 1142static int ssd132x_primary_plane_atomic_check(struct drm_plane *plane,1143					      struct drm_atomic_state *state)1144{1145	struct drm_device *drm = plane->dev;1146	struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);1147	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);1148	struct ssd130x_plane_state *ssd130x_state = to_ssd130x_plane_state(plane_state);1149	struct drm_shadow_plane_state *shadow_plane_state = &ssd130x_state->base;1150	struct drm_crtc *crtc = plane_state->crtc;1151	struct drm_crtc_state *crtc_state = NULL;1152	const struct drm_format_info *fi;1153	unsigned int pitch;1154	int ret;1155 1156	if (crtc)1157		crtc_state = drm_atomic_get_new_crtc_state(state, crtc);1158 1159	ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,1160						  DRM_PLANE_NO_SCALING,1161						  DRM_PLANE_NO_SCALING,1162						  false, false);1163	if (ret)1164		return ret;1165	else if (!plane_state->visible)1166		return 0;1167 1168	fi = drm_format_info(DRM_FORMAT_R8);1169	if (!fi)1170		return -EINVAL;1171 1172	pitch = drm_format_info_min_pitch(fi, 0, ssd130x->width);1173 1174	if (plane_state->fb->format != fi) {1175		void *buf;1176 1177		/* format conversion necessary; reserve buffer */1178		buf = drm_format_conv_state_reserve(&shadow_plane_state->fmtcnv_state,1179						    pitch, GFP_KERNEL);1180		if (!buf)1181			return -ENOMEM;1182	}1183 1184	ssd130x_state->buffer = kcalloc(pitch, ssd130x->height, GFP_KERNEL);1185	if (!ssd130x_state->buffer)1186		return -ENOMEM;1187 1188	return 0;1189}1190 1191static int ssd133x_primary_plane_atomic_check(struct drm_plane *plane,1192					      struct drm_atomic_state *state)1193{1194	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);1195	struct drm_crtc *crtc = plane_state->crtc;1196	struct drm_crtc_state *crtc_state = NULL;1197	int ret;1198 1199	if (crtc)1200		crtc_state = drm_atomic_get_new_crtc_state(state, crtc);1201 1202	ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,1203						  DRM_PLANE_NO_SCALING,1204						  DRM_PLANE_NO_SCALING,1205						  false, false);1206	if (ret)1207		return ret;1208	else if (!plane_state->visible)1209		return 0;1210 1211	return 0;1212}1213 1214static void ssd130x_primary_plane_atomic_update(struct drm_plane *plane,1215						struct drm_atomic_state *state)1216{1217	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);1218	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);1219	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);1220	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);1221	struct ssd130x_crtc_state *ssd130x_crtc_state =  to_ssd130x_crtc_state(crtc_state);1222	struct ssd130x_plane_state *ssd130x_plane_state = to_ssd130x_plane_state(plane_state);1223	struct drm_framebuffer *fb = plane_state->fb;1224	struct drm_atomic_helper_damage_iter iter;1225	struct drm_device *drm = plane->dev;1226	struct drm_rect dst_clip;1227	struct drm_rect damage;1228	int idx;1229 1230	if (!drm_dev_enter(drm, &idx))1231		return;1232 1233	drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);1234	drm_atomic_for_each_plane_damage(&iter, &damage) {1235		dst_clip = plane_state->dst;1236 1237		if (!drm_rect_intersect(&dst_clip, &damage))1238			continue;1239 1240		ssd130x_fb_blit_rect(fb, &shadow_plane_state->data[0], &dst_clip,1241				     ssd130x_plane_state->buffer,1242				     ssd130x_crtc_state->data_array,1243				     &shadow_plane_state->fmtcnv_state);1244	}1245 1246	drm_dev_exit(idx);1247}1248 1249static void ssd132x_primary_plane_atomic_update(struct drm_plane *plane,1250						struct drm_atomic_state *state)1251{1252	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);1253	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);1254	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);1255	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);1256	struct ssd130x_crtc_state *ssd130x_crtc_state =  to_ssd130x_crtc_state(crtc_state);1257	struct ssd130x_plane_state *ssd130x_plane_state = to_ssd130x_plane_state(plane_state);1258	struct drm_framebuffer *fb = plane_state->fb;1259	struct drm_atomic_helper_damage_iter iter;1260	struct drm_device *drm = plane->dev;1261	struct drm_rect dst_clip;1262	struct drm_rect damage;1263	int idx;1264 1265	if (!drm_dev_enter(drm, &idx))1266		return;1267 1268	drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);1269	drm_atomic_for_each_plane_damage(&iter, &damage) {1270		dst_clip = plane_state->dst;1271 1272		if (!drm_rect_intersect(&dst_clip, &damage))1273			continue;1274 1275		ssd132x_fb_blit_rect(fb, &shadow_plane_state->data[0], &dst_clip,1276				     ssd130x_plane_state->buffer,1277				     ssd130x_crtc_state->data_array,1278				     &shadow_plane_state->fmtcnv_state);1279	}1280 1281	drm_dev_exit(idx);1282}1283 1284static void ssd133x_primary_plane_atomic_update(struct drm_plane *plane,1285						struct drm_atomic_state *state)1286{1287	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);1288	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);1289	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);1290	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);1291	struct ssd130x_crtc_state *ssd130x_crtc_state =  to_ssd130x_crtc_state(crtc_state);1292	struct drm_framebuffer *fb = plane_state->fb;1293	struct drm_atomic_helper_damage_iter iter;1294	struct drm_device *drm = plane->dev;1295	struct drm_rect dst_clip;1296	struct drm_rect damage;1297	int idx;1298 1299	if (!drm_dev_enter(drm, &idx))1300		return;1301 1302	drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);1303	drm_atomic_for_each_plane_damage(&iter, &damage) {1304		dst_clip = plane_state->dst;1305 1306		if (!drm_rect_intersect(&dst_clip, &damage))1307			continue;1308 1309		ssd133x_fb_blit_rect(fb, &shadow_plane_state->data[0], &dst_clip,1310				     ssd130x_crtc_state->data_array,1311				     &shadow_plane_state->fmtcnv_state);1312	}1313 1314	drm_dev_exit(idx);1315}1316 1317static void ssd130x_primary_plane_atomic_disable(struct drm_plane *plane,1318						 struct drm_atomic_state *state)1319{1320	struct drm_device *drm = plane->dev;1321	struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);1322	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);1323	struct drm_crtc_state *crtc_state;1324	struct ssd130x_crtc_state *ssd130x_crtc_state;1325	int idx;1326 1327	if (!plane_state->crtc)1328		return;1329 1330	crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);1331	ssd130x_crtc_state = to_ssd130x_crtc_state(crtc_state);1332 1333	if (!drm_dev_enter(drm, &idx))1334		return;1335 1336	ssd130x_clear_screen(ssd130x, ssd130x_crtc_state->data_array);1337 1338	drm_dev_exit(idx);1339}1340 1341static void ssd132x_primary_plane_atomic_disable(struct drm_plane *plane,1342						 struct drm_atomic_state *state)1343{1344	struct drm_device *drm = plane->dev;1345	struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);1346	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);1347	struct drm_crtc_state *crtc_state;1348	struct ssd130x_crtc_state *ssd130x_crtc_state;1349	int idx;1350 1351	if (!plane_state->crtc)1352		return;1353 1354	crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);1355	ssd130x_crtc_state = to_ssd130x_crtc_state(crtc_state);1356 1357	if (!drm_dev_enter(drm, &idx))1358		return;1359 1360	ssd132x_clear_screen(ssd130x, ssd130x_crtc_state->data_array);1361 1362	drm_dev_exit(idx);1363}1364 1365static void ssd133x_primary_plane_atomic_disable(struct drm_plane *plane,1366						 struct drm_atomic_state *state)1367{1368	struct drm_device *drm = plane->dev;1369	struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);1370	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);1371	struct drm_crtc_state *crtc_state;1372	struct ssd130x_crtc_state *ssd130x_crtc_state;1373	int idx;1374 1375	if (!plane_state->crtc)1376		return;1377 1378	crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);1379	ssd130x_crtc_state = to_ssd130x_crtc_state(crtc_state);1380 1381	if (!drm_dev_enter(drm, &idx))1382		return;1383 1384	ssd133x_clear_screen(ssd130x, ssd130x_crtc_state->data_array);1385 1386	drm_dev_exit(idx);1387}1388 1389/* Called during init to allocate the plane's atomic state. */1390static void ssd130x_primary_plane_reset(struct drm_plane *plane)1391{1392	struct ssd130x_plane_state *ssd130x_state;1393 1394	WARN_ON(plane->state);1395 1396	ssd130x_state = kzalloc(sizeof(*ssd130x_state), GFP_KERNEL);1397	if (!ssd130x_state)1398		return;1399 1400	__drm_gem_reset_shadow_plane(plane, &ssd130x_state->base);1401}1402 1403static struct drm_plane_state *ssd130x_primary_plane_duplicate_state(struct drm_plane *plane)1404{1405	struct drm_shadow_plane_state *new_shadow_plane_state;1406	struct ssd130x_plane_state *old_ssd130x_state;1407	struct ssd130x_plane_state *ssd130x_state;1408 1409	if (WARN_ON(!plane->state))1410		return NULL;1411 1412	old_ssd130x_state = to_ssd130x_plane_state(plane->state);1413	ssd130x_state = kmemdup(old_ssd130x_state, sizeof(*ssd130x_state), GFP_KERNEL);1414	if (!ssd130x_state)1415		return NULL;1416 1417	/* The buffer is not duplicated and is allocated in .atomic_check */1418	ssd130x_state->buffer = NULL;1419 1420	new_shadow_plane_state = &ssd130x_state->base;1421 1422	__drm_gem_duplicate_shadow_plane_state(plane, new_shadow_plane_state);1423 1424	return &new_shadow_plane_state->base;1425}1426 1427static void ssd130x_primary_plane_destroy_state(struct drm_plane *plane,1428						struct drm_plane_state *state)1429{1430	struct ssd130x_plane_state *ssd130x_state = to_ssd130x_plane_state(state);1431 1432	kfree(ssd130x_state->buffer);1433 1434	__drm_gem_destroy_shadow_plane_state(&ssd130x_state->base);1435 1436	kfree(ssd130x_state);1437}1438 1439static const struct drm_plane_helper_funcs ssd130x_primary_plane_helper_funcs[] = {1440	[SSD130X_FAMILY] = {1441		DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,1442		.atomic_check = ssd130x_primary_plane_atomic_check,1443		.atomic_update = ssd130x_primary_plane_atomic_update,1444		.atomic_disable = ssd130x_primary_plane_atomic_disable,1445	},1446	[SSD132X_FAMILY] = {1447		DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,1448		.atomic_check = ssd132x_primary_plane_atomic_check,1449		.atomic_update = ssd132x_primary_plane_atomic_update,1450		.atomic_disable = ssd132x_primary_plane_atomic_disable,1451	},1452	[SSD133X_FAMILY] = {1453		DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,1454		.atomic_check = ssd133x_primary_plane_atomic_check,1455		.atomic_update = ssd133x_primary_plane_atomic_update,1456		.atomic_disable = ssd133x_primary_plane_atomic_disable,1457	}1458};1459 1460static const struct drm_plane_funcs ssd130x_primary_plane_funcs = {1461	.update_plane = drm_atomic_helper_update_plane,1462	.disable_plane = drm_atomic_helper_disable_plane,1463	.reset = ssd130x_primary_plane_reset,1464	.atomic_duplicate_state = ssd130x_primary_plane_duplicate_state,1465	.atomic_destroy_state = ssd130x_primary_plane_destroy_state,1466	.destroy = drm_plane_cleanup,1467};1468 1469static enum drm_mode_status ssd130x_crtc_mode_valid(struct drm_crtc *crtc,1470						    const struct drm_display_mode *mode)1471{1472	struct ssd130x_device *ssd130x = drm_to_ssd130x(crtc->dev);1473 1474	if (mode->hdisplay != ssd130x->mode.hdisplay &&1475	    mode->vdisplay != ssd130x->mode.vdisplay)1476		return MODE_ONE_SIZE;1477	else if (mode->hdisplay != ssd130x->mode.hdisplay)1478		return MODE_ONE_WIDTH;1479	else if (mode->vdisplay != ssd130x->mode.vdisplay)1480		return MODE_ONE_HEIGHT;1481 1482	return MODE_OK;1483}1484 1485static int ssd130x_crtc_atomic_check(struct drm_crtc *crtc,1486				     struct drm_atomic_state *state)1487{1488	struct drm_device *drm = crtc->dev;1489	struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);1490	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);1491	struct ssd130x_crtc_state *ssd130x_state = to_ssd130x_crtc_state(crtc_state);1492	unsigned int pages = DIV_ROUND_UP(ssd130x->height, SSD130X_PAGE_HEIGHT);1493	int ret;1494 1495	ret = drm_crtc_helper_atomic_check(crtc, state);1496	if (ret)1497		return ret;1498 1499	ssd130x_state->data_array = kmalloc(ssd130x->width * pages, GFP_KERNEL);1500	if (!ssd130x_state->data_array)1501		return -ENOMEM;1502 1503	return 0;1504}1505 1506static int ssd132x_crtc_atomic_check(struct drm_crtc *crtc,1507				     struct drm_atomic_state *state)1508{1509	struct drm_device *drm = crtc->dev;1510	struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);1511	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);1512	struct ssd130x_crtc_state *ssd130x_state = to_ssd130x_crtc_state(crtc_state);1513	unsigned int columns = DIV_ROUND_UP(ssd130x->width, SSD132X_SEGMENT_WIDTH);1514	int ret;1515 1516	ret = drm_crtc_helper_atomic_check(crtc, state);1517	if (ret)1518		return ret;1519 1520	ssd130x_state->data_array = kmalloc(columns * ssd130x->height, GFP_KERNEL);1521	if (!ssd130x_state->data_array)1522		return -ENOMEM;1523 1524	return 0;1525}1526 1527static int ssd133x_crtc_atomic_check(struct drm_crtc *crtc,1528				     struct drm_atomic_state *state)1529{1530	struct drm_device *drm = crtc->dev;1531	struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);1532	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);1533	struct ssd130x_crtc_state *ssd130x_state = to_ssd130x_crtc_state(crtc_state);1534	const struct drm_format_info *fi = drm_format_info(DRM_FORMAT_RGB332);1535	unsigned int pitch;1536	int ret;1537 1538	if (!fi)1539		return -EINVAL;1540 1541	ret = drm_crtc_helper_atomic_check(crtc, state);1542	if (ret)1543		return ret;1544 1545	pitch = drm_format_info_min_pitch(fi, 0, ssd130x->width);1546 1547	ssd130x_state->data_array = kmalloc(pitch * ssd130x->height, GFP_KERNEL);1548	if (!ssd130x_state->data_array)1549		return -ENOMEM;1550 1551	return 0;1552}1553 1554/* Called during init to allocate the CRTC's atomic state. */1555static void ssd130x_crtc_reset(struct drm_crtc *crtc)1556{1557	struct ssd130x_crtc_state *ssd130x_state;1558 1559	WARN_ON(crtc->state);1560 1561	ssd130x_state = kzalloc(sizeof(*ssd130x_state), GFP_KERNEL);1562	if (!ssd130x_state)1563		return;1564 1565	__drm_atomic_helper_crtc_reset(crtc, &ssd130x_state->base);1566}1567 1568static struct drm_crtc_state *ssd130x_crtc_duplicate_state(struct drm_crtc *crtc)1569{1570	struct ssd130x_crtc_state *old_ssd130x_state;1571	struct ssd130x_crtc_state *ssd130x_state;1572 1573	if (WARN_ON(!crtc->state))1574		return NULL;1575 1576	old_ssd130x_state = to_ssd130x_crtc_state(crtc->state);1577	ssd130x_state = kmemdup(old_ssd130x_state, sizeof(*ssd130x_state), GFP_KERNEL);1578	if (!ssd130x_state)1579		return NULL;1580 1581	/* The buffer is not duplicated and is allocated in .atomic_check */1582	ssd130x_state->data_array = NULL;1583 1584	__drm_atomic_helper_crtc_duplicate_state(crtc, &ssd130x_state->base);1585 1586	return &ssd130x_state->base;1587}1588 1589static void ssd130x_crtc_destroy_state(struct drm_crtc *crtc,1590				       struct drm_crtc_state *state)1591{1592	struct ssd130x_crtc_state *ssd130x_state = to_ssd130x_crtc_state(state);1593 1594	kfree(ssd130x_state->data_array);1595 1596	__drm_atomic_helper_crtc_destroy_state(state);1597 1598	kfree(ssd130x_state);1599}1600 1601/*1602 * The CRTC is always enabled. Screen updates are performed by1603 * the primary plane's atomic_update function. Disabling clears1604 * the screen in the primary plane's atomic_disable function.1605 */1606static const struct drm_crtc_helper_funcs ssd130x_crtc_helper_funcs[] = {1607	[SSD130X_FAMILY] = {1608		.mode_valid = ssd130x_crtc_mode_valid,1609		.atomic_check = ssd130x_crtc_atomic_check,1610	},1611	[SSD132X_FAMILY] = {1612		.mode_valid = ssd130x_crtc_mode_valid,1613		.atomic_check = ssd132x_crtc_atomic_check,1614	},1615	[SSD133X_FAMILY] = {1616		.mode_valid = ssd130x_crtc_mode_valid,1617		.atomic_check = ssd133x_crtc_atomic_check,1618	},1619};1620 1621static const struct drm_crtc_funcs ssd130x_crtc_funcs = {1622	.reset = ssd130x_crtc_reset,1623	.destroy = drm_crtc_cleanup,1624	.set_config = drm_atomic_helper_set_config,1625	.page_flip = drm_atomic_helper_page_flip,1626	.atomic_duplicate_state = ssd130x_crtc_duplicate_state,1627	.atomic_destroy_state = ssd130x_crtc_destroy_state,1628};1629 1630static void ssd130x_encoder_atomic_enable(struct drm_encoder *encoder,1631					  struct drm_atomic_state *state)1632{1633	struct drm_device *drm = encoder->dev;1634	struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);1635	int ret;1636 1637	ret = ssd130x_power_on(ssd130x);1638	if (ret)1639		return;1640 1641	ret = ssd130x_init(ssd130x);1642	if (ret)1643		goto power_off;1644 1645	ssd130x_write_cmd(ssd130x, 1, SSD13XX_DISPLAY_ON);1646 1647	backlight_enable(ssd130x->bl_dev);1648 1649	return;1650 1651power_off:1652	ssd130x_power_off(ssd130x);1653	return;1654}1655 1656static void ssd132x_encoder_atomic_enable(struct drm_encoder *encoder,1657					  struct drm_atomic_state *state)1658{1659	struct drm_device *drm = encoder->dev;1660	struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);1661	int ret;1662 1663	ret = ssd130x_power_on(ssd130x);1664	if (ret)1665		return;1666 1667	ret = ssd132x_init(ssd130x);1668	if (ret)1669		goto power_off;1670 1671	ssd130x_write_cmd(ssd130x, 1, SSD13XX_DISPLAY_ON);1672 1673	backlight_enable(ssd130x->bl_dev);1674 1675	return;1676 1677power_off:1678	ssd130x_power_off(ssd130x);1679}1680 1681static void ssd133x_encoder_atomic_enable(struct drm_encoder *encoder,1682					  struct drm_atomic_state *state)1683{1684	struct drm_device *drm = encoder->dev;1685	struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);1686	int ret;1687 1688	ret = ssd130x_power_on(ssd130x);1689	if (ret)1690		return;1691 1692	ret = ssd133x_init(ssd130x);1693	if (ret)1694		goto power_off;1695 1696	ssd130x_write_cmd(ssd130x, 1, SSD13XX_DISPLAY_ON);1697 1698	backlight_enable(ssd130x->bl_dev);1699 1700	return;1701 1702power_off:1703	ssd130x_power_off(ssd130x);1704}1705 1706static void ssd130x_encoder_atomic_disable(struct drm_encoder *encoder,1707					   struct drm_atomic_state *state)1708{1709	struct drm_device *drm = encoder->dev;1710	struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);1711 1712	backlight_disable(ssd130x->bl_dev);1713 1714	ssd130x_write_cmd(ssd130x, 1, SSD13XX_DISPLAY_OFF);1715 1716	ssd130x_power_off(ssd130x);1717}1718 1719static const struct drm_encoder_helper_funcs ssd130x_encoder_helper_funcs[] = {1720	[SSD130X_FAMILY] = {1721		.atomic_enable = ssd130x_encoder_atomic_enable,1722		.atomic_disable = ssd130x_encoder_atomic_disable,1723	},1724	[SSD132X_FAMILY] = {1725		.atomic_enable = ssd132x_encoder_atomic_enable,1726		.atomic_disable = ssd130x_encoder_atomic_disable,1727	},1728	[SSD133X_FAMILY] = {1729		.atomic_enable = ssd133x_encoder_atomic_enable,1730		.atomic_disable = ssd130x_encoder_atomic_disable,1731	}1732};1733 1734static const struct drm_encoder_funcs ssd130x_encoder_funcs = {1735	.destroy = drm_encoder_cleanup,1736};1737 1738static int ssd130x_connector_get_modes(struct drm_connector *connector)1739{1740	struct ssd130x_device *ssd130x = drm_to_ssd130x(connector->dev);1741	struct drm_display_mode *mode;1742	struct device *dev = ssd130x->dev;1743 1744	mode = drm_mode_duplicate(connector->dev, &ssd130x->mode);1745	if (!mode) {1746		dev_err(dev, "Failed to duplicated mode\n");1747		return 0;1748	}1749 1750	drm_mode_probed_add(connector, mode);1751	drm_set_preferred_mode(connector, mode->hdisplay, mode->vdisplay);1752 1753	/* There is only a single mode */1754	return 1;1755}1756 1757static const struct drm_connector_helper_funcs ssd130x_connector_helper_funcs = {1758	.get_modes = ssd130x_connector_get_modes,1759};1760 1761static const struct drm_connector_funcs ssd130x_connector_funcs = {1762	.reset = drm_atomic_helper_connector_reset,1763	.fill_modes = drm_helper_probe_single_connector_modes,1764	.destroy = drm_connector_cleanup,1765	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,1766	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,1767};1768 1769static const struct drm_mode_config_funcs ssd130x_mode_config_funcs = {1770	.fb_create = drm_gem_fb_create_with_dirty,1771	.atomic_check = drm_atomic_helper_check,1772	.atomic_commit = drm_atomic_helper_commit,1773};1774 1775static const uint32_t ssd130x_formats[] = {1776	DRM_FORMAT_XRGB8888,1777};1778 1779DEFINE_DRM_GEM_FOPS(ssd130x_fops);1780 1781static const struct drm_driver ssd130x_drm_driver = {1782	DRM_GEM_SHMEM_DRIVER_OPS,1783	.name			= DRIVER_NAME,1784	.desc			= DRIVER_DESC,1785	.date			= DRIVER_DATE,1786	.major			= DRIVER_MAJOR,1787	.minor			= DRIVER_MINOR,1788	.driver_features	= DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,1789	.fops			= &ssd130x_fops,1790};1791 1792static int ssd130x_update_bl(struct backlight_device *bdev)1793{1794	struct ssd130x_device *ssd130x = bl_get_data(bdev);1795	int brightness = backlight_get_brightness(bdev);1796	int ret;1797 1798	ssd130x->contrast = brightness;1799 1800	ret = ssd130x_write_cmd(ssd130x, 1, SSD13XX_CONTRAST);1801	if (ret < 0)1802		return ret;1803 1804	ret = ssd130x_write_cmd(ssd130x, 1, ssd130x->contrast);1805	if (ret < 0)1806		return ret;1807 1808	return 0;1809}1810 1811static const struct backlight_ops ssd130xfb_bl_ops = {1812	.update_status	= ssd130x_update_bl,1813};1814 1815static void ssd130x_parse_properties(struct ssd130x_device *ssd130x)1816{1817	struct device *dev = ssd130x->dev;1818 1819	if (device_property_read_u32(dev, "solomon,width", &ssd130x->width))1820		ssd130x->width = ssd130x->device_info->default_width;1821 1822	if (device_property_read_u32(dev, "solomon,height", &ssd130x->height))1823		ssd130x->height = ssd130x->device_info->default_height;1824 1825	if (device_property_read_u32(dev, "solomon,page-offset", &ssd130x->page_offset))1826		ssd130x->page_offset = 1;1827 1828	if (device_property_read_u32(dev, "solomon,col-offset", &ssd130x->col_offset))1829		ssd130x->col_offset = 0;1830 1831	if (device_property_read_u32(dev, "solomon,com-offset", &ssd130x->com_offset))1832		ssd130x->com_offset = 0;1833 1834	if (device_property_read_u32(dev, "solomon,prechargep1", &ssd130x->prechargep1))1835		ssd130x->prechargep1 = 2;1836 1837	if (device_property_read_u32(dev, "solomon,prechargep2", &ssd130x->prechargep2))1838		ssd130x->prechargep2 = 2;1839 1840	if (!device_property_read_u8_array(dev, "solomon,lookup-table",1841					   ssd130x->lookup_table,1842					   ARRAY_SIZE(ssd130x->lookup_table)))1843		ssd130x->lookup_table_set = 1;1844 1845	ssd130x->seg_remap = !device_property_read_bool(dev, "solomon,segment-no-remap");1846	ssd130x->com_seq = device_property_read_bool(dev, "solomon,com-seq");1847	ssd130x->com_lrremap = device_property_read_bool(dev, "solomon,com-lrremap");1848	ssd130x->com_invdir = device_property_read_bool(dev, "solomon,com-invdir");1849	ssd130x->area_color_enable =1850		device_property_read_bool(dev, "solomon,area-color-enable");1851	ssd130x->low_power = device_property_read_bool(dev, "solomon,low-power");1852 1853	ssd130x->contrast = 127;1854	ssd130x->vcomh = ssd130x->device_info->default_vcomh;1855 1856	/* Setup display timing */1857	if (device_property_read_u32(dev, "solomon,dclk-div", &ssd130x->dclk_div))1858		ssd130x->dclk_div = ssd130x->device_info->default_dclk_div;1859	if (device_property_read_u32(dev, "solomon,dclk-frq", &ssd130x->dclk_frq))1860		ssd130x->dclk_frq = ssd130x->device_info->default_dclk_frq;1861}1862 1863static int ssd130x_init_modeset(struct ssd130x_device *ssd130x)1864{1865	enum ssd130x_family_ids family_id = ssd130x->device_info->family_id;1866	struct drm_display_mode *mode = &ssd130x->mode;1867	struct device *dev = ssd130x->dev;1868	struct drm_device *drm = &ssd130x->drm;1869	unsigned long max_width, max_height;1870	struct drm_plane *primary_plane;1871	struct drm_crtc *crtc;1872	struct drm_encoder *encoder;1873	struct drm_connector *connector;1874	int ret;1875 1876	/*1877	 * Modesetting1878	 */1879 1880	ret = drmm_mode_config_init(drm);1881	if (ret) {1882		dev_err(dev, "DRM mode config init failed: %d\n", ret);1883		return ret;1884	}1885 1886	mode->type = DRM_MODE_TYPE_DRIVER;1887	mode->clock = 1;1888	mode->hdisplay = mode->htotal = ssd130x->width;1889	mode->hsync_start = mode->hsync_end = ssd130x->width;1890	mode->vdisplay = mode->vtotal = ssd130x->height;1891	mode->vsync_start = mode->vsync_end = ssd130x->height;1892	mode->width_mm = 27;1893	mode->height_mm = 27;1894 1895	max_width = max_t(unsigned long, mode->hdisplay, DRM_SHADOW_PLANE_MAX_WIDTH);1896	max_height = max_t(unsigned long, mode->vdisplay, DRM_SHADOW_PLANE_MAX_HEIGHT);1897 1898	drm->mode_config.min_width = mode->hdisplay;1899	drm->mode_config.max_width = max_width;1900	drm->mode_config.min_height = mode->vdisplay;1901	drm->mode_config.max_height = max_height;1902	drm->mode_config.preferred_depth = 24;1903	drm->mode_config.funcs = &ssd130x_mode_config_funcs;1904 1905	/* Primary plane */1906 1907	primary_plane = &ssd130x->primary_plane;1908	ret = drm_universal_plane_init(drm, primary_plane, 0, &ssd130x_primary_plane_funcs,1909				       ssd130x_formats, ARRAY_SIZE(ssd130x_formats),1910				       NULL, DRM_PLANE_TYPE_PRIMARY, NULL);1911	if (ret) {1912		dev_err(dev, "DRM primary plane init failed: %d\n", ret);1913		return ret;1914	}1915 1916	drm_plane_helper_add(primary_plane, &ssd130x_primary_plane_helper_funcs[family_id]);1917 1918	drm_plane_enable_fb_damage_clips(primary_plane);1919 1920	/* CRTC */1921 1922	crtc = &ssd130x->crtc;1923	ret = drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,1924					&ssd130x_crtc_funcs, NULL);1925	if (ret) {1926		dev_err(dev, "DRM crtc init failed: %d\n", ret);1927		return ret;1928	}1929 1930	drm_crtc_helper_add(crtc, &ssd130x_crtc_helper_funcs[family_id]);1931 1932	/* Encoder */1933 1934	encoder = &ssd130x->encoder;1935	ret = drm_encoder_init(drm, encoder, &ssd130x_encoder_funcs,1936			       DRM_MODE_ENCODER_NONE, NULL);1937	if (ret) {1938		dev_err(dev, "DRM encoder init failed: %d\n", ret);1939		return ret;1940	}1941 1942	drm_encoder_helper_add(encoder, &ssd130x_encoder_helper_funcs[family_id]);1943 1944	encoder->possible_crtcs = drm_crtc_mask(crtc);1945 1946	/* Connector */1947 1948	connector = &ssd130x->connector;1949	ret = drm_connector_init(drm, connector, &ssd130x_connector_funcs,1950				 DRM_MODE_CONNECTOR_Unknown);1951	if (ret) {1952		dev_err(dev, "DRM connector init failed: %d\n", ret);1953		return ret;1954	}1955 1956	drm_connector_helper_add(connector, &ssd130x_connector_helper_funcs);1957 1958	ret = drm_connector_attach_encoder(connector, encoder);1959	if (ret) {1960		dev_err(dev, "DRM attach connector to encoder failed: %d\n", ret);1961		return ret;1962	}1963 1964	drm_mode_config_reset(drm);1965 1966	return 0;1967}1968 1969static int ssd130x_get_resources(struct ssd130x_device *ssd130x)1970{1971	struct device *dev = ssd130x->dev;1972 1973	ssd130x->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);1974	if (IS_ERR(ssd130x->reset))1975		return dev_err_probe(dev, PTR_ERR(ssd130x->reset),1976				     "Failed to get reset gpio\n");1977 1978	ssd130x->vcc_reg = devm_regulator_get(dev, "vcc");1979	if (IS_ERR(ssd130x->vcc_reg))1980		return dev_err_probe(dev, PTR_ERR(ssd130x->vcc_reg),1981				     "Failed to get VCC regulator\n");1982 1983	return 0;1984}1985 1986struct ssd130x_device *ssd130x_probe(struct device *dev, struct regmap *regmap)1987{1988	struct ssd130x_device *ssd130x;1989	struct backlight_device *bl;1990	struct drm_device *drm;1991	int ret;1992 1993	ssd130x = devm_drm_dev_alloc(dev, &ssd130x_drm_driver,1994				     struct ssd130x_device, drm);1995	if (IS_ERR(ssd130x))1996		return ERR_PTR(dev_err_probe(dev, PTR_ERR(ssd130x),1997					     "Failed to allocate DRM device\n"));1998 1999	drm = &ssd130x->drm;2000 2001	ssd130x->dev = dev;2002	ssd130x->regmap = regmap;2003	ssd130x->device_info = device_get_match_data(dev);2004 2005	if (ssd130x->device_info->page_mode_only)2006		ssd130x->page_address_mode = 1;2007 2008	ssd130x_parse_properties(ssd130x);2009 2010	ret = ssd130x_get_resources(ssd130x);2011	if (ret)2012		return ERR_PTR(ret);2013 2014	bl = devm_backlight_device_register(dev, dev_name(dev), dev, ssd130x,2015					    &ssd130xfb_bl_ops, NULL);2016	if (IS_ERR(bl))2017		return ERR_PTR(dev_err_probe(dev, PTR_ERR(bl),2018					     "Unable to register backlight device\n"));2019 2020	bl->props.brightness = ssd130x->contrast;2021	bl->props.max_brightness = MAX_CONTRAST;2022	ssd130x->bl_dev = bl;2023 2024	ret = ssd130x_init_modeset(ssd130x);2025	if (ret)2026		return ERR_PTR(ret);2027 2028	ret = drm_dev_register(drm, 0);2029	if (ret)2030		return ERR_PTR(dev_err_probe(dev, ret, "DRM device register failed\n"));2031 2032	drm_fbdev_shmem_setup(drm, 32);2033 2034	return ssd130x;2035}2036EXPORT_SYMBOL_GPL(ssd130x_probe);2037 2038void ssd130x_remove(struct ssd130x_device *ssd130x)2039{2040	drm_dev_unplug(&ssd130x->drm);2041	drm_atomic_helper_shutdown(&ssd130x->drm);2042}2043EXPORT_SYMBOL_GPL(ssd130x_remove);2044 2045void ssd130x_shutdown(struct ssd130x_device *ssd130x)2046{2047	drm_atomic_helper_shutdown(&ssd130x->drm);2048}2049EXPORT_SYMBOL_GPL(ssd130x_shutdown);2050 2051MODULE_DESCRIPTION(DRIVER_DESC);2052MODULE_AUTHOR("Javier Martinez Canillas <javierm@redhat.com>");2053MODULE_LICENSE("GPL v2");2054