1155 lines · 28.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * DRM driver for Pervasive Displays RePaper branded e-ink panels * * Copyright 2013-2017 Pervasive Displays, Inc. * Copyright 2017 Noralf Trønnes * * The driver supports: * Material Film: Aurora Mb (V231) * Driver IC: G2 (eTC) * * The controller code was taken from the userspace driver: * https://github.com/repaper/gratis */ #include <linux/delay.h>#include <linux/gpio/consumer.h>#include <linux/module.h>#include <linux/property.h>#include <linux/sched/clock.h>#include <linux/spi/spi.h>#include <linux/thermal.h> #include <drm/drm_atomic_helper.h>#include <drm/drm_client_setup.h>#include <drm/drm_connector.h>#include <drm/drm_damage_helper.h>#include <drm/drm_drv.h>#include <drm/drm_fb_dma_helper.h>#include <drm/drm_fbdev_dma.h>#include <drm/drm_format_helper.h>#include <drm/drm_framebuffer.h>#include <drm/drm_gem_atomic_helper.h>#include <drm/drm_gem_dma_helper.h>#include <drm/drm_gem_framebuffer_helper.h>#include <drm/drm_managed.h>#include <drm/drm_modes.h>#include <drm/drm_rect.h>#include <drm/drm_probe_helper.h>#include <drm/drm_simple_kms_helper.h> #define REPAPER_RID_G2_COG_ID	0x12 enum repaper_model {	/* 0 is reserved to avoid clashing with NULL */	E1144CS021 = 1,	E1190CS021,	E2200CS021,	E2271CS021,}; enum repaper_stage {         /* Image pixel -> Display pixel */	REPAPER_COMPENSATE,  /* B -> W, W -> B (Current Image) */	REPAPER_WHITE,       /* B -> N, W -> W (Current Image) */	REPAPER_INVERSE,     /* B -> N, W -> B (New Image) */	REPAPER_NORMAL       /* B -> B, W -> W (New Image) */}; enum repaper_epd_border_byte {	REPAPER_BORDER_BYTE_NONE,	REPAPER_BORDER_BYTE_ZERO,	REPAPER_BORDER_BYTE_SET,}; struct repaper_epd {	struct drm_device drm;	struct drm_simple_display_pipe pipe;	const struct drm_display_mode *mode;	struct drm_connector connector;	struct spi_device *spi; 	struct gpio_desc *panel_on;	struct gpio_desc *border;	struct gpio_desc *discharge;	struct gpio_desc *reset;	struct gpio_desc *busy; 	struct thermal_zone_device *thermal; 	unsigned int height;	unsigned int width;	unsigned int bytes_per_scan;	const u8 *channel_select;	unsigned int stage_time;	unsigned int factored_stage_time;	bool middle_scan;	bool pre_border_byte;	enum repaper_epd_border_byte border_byte; 	u8 *line_buffer;	void *current_frame; 	bool cleared;	bool partial;}; static inline struct repaper_epd *drm_to_epd(struct drm_device *drm){	return container_of(drm, struct repaper_epd, drm);} static int repaper_spi_transfer(struct spi_device *spi, u8 header,				const void *tx, void *rx, size_t len){	void *txbuf = NULL, *rxbuf = NULL;	struct spi_transfer tr[2] = {};	u8 *headerbuf;	int ret; 	headerbuf = kmalloc(1, GFP_KERNEL);	if (!headerbuf)		return -ENOMEM; 	headerbuf[0] = header;	tr[0].tx_buf = headerbuf;	tr[0].len = 1; 	/* Stack allocated tx? */	if (tx && len <= 32) {		txbuf = kmemdup(tx, len, GFP_KERNEL);		if (!txbuf) {			ret = -ENOMEM;			goto out_free;		}	} 	if (rx) {		rxbuf = kmalloc(len, GFP_KERNEL);		if (!rxbuf) {			ret = -ENOMEM;			goto out_free;		}	} 	tr[1].tx_buf = txbuf ? txbuf : tx;	tr[1].rx_buf = rxbuf;	tr[1].len = len; 	ndelay(80);	ret = spi_sync_transfer(spi, tr, 2);	if (rx && !ret)		memcpy(rx, rxbuf, len); out_free:	kfree(headerbuf);	kfree(txbuf);	kfree(rxbuf); 	return ret;} static int repaper_write_buf(struct spi_device *spi, u8 reg,			     const u8 *buf, size_t len){	int ret; 	ret = repaper_spi_transfer(spi, 0x70, &reg, NULL, 1);	if (ret)		return ret; 	return repaper_spi_transfer(spi, 0x72, buf, NULL, len);} static int repaper_write_val(struct spi_device *spi, u8 reg, u8 val){	return repaper_write_buf(spi, reg, &val, 1);} static int repaper_read_val(struct spi_device *spi, u8 reg){	int ret;	u8 val; 	ret = repaper_spi_transfer(spi, 0x70, &reg, NULL, 1);	if (ret)		return ret; 	ret = repaper_spi_transfer(spi, 0x73, NULL, &val, 1); 	return ret ? ret : val;} static int repaper_read_id(struct spi_device *spi){	int ret;	u8 id; 	ret = repaper_spi_transfer(spi, 0x71, NULL, &id, 1); 	return ret ? ret : id;} static void repaper_spi_mosi_low(struct spi_device *spi){	const u8 buf[1] = { 0 }; 	spi_write(spi, buf, 1);} /* pixels on display are numbered from 1 so even is actually bits 1,3,5,... */static void repaper_even_pixels(struct repaper_epd *epd, u8 **pp,				const u8 *data, u8 fixed_value, const u8 *mask,				enum repaper_stage stage){	unsigned int b; 	for (b = 0; b < (epd->width / 8); b++) {		if (data) {			u8 pixels = data[b] & 0xaa;			u8 pixel_mask = 0xff;			u8 p1, p2, p3, p4; 			if (mask) {				pixel_mask = (mask[b] ^ pixels) & 0xaa;				pixel_mask |= pixel_mask >> 1;			} 			switch (stage) {			case REPAPER_COMPENSATE: /* B -> W, W -> B (Current) */				pixels = 0xaa | ((pixels ^ 0xaa) >> 1);				break;			case REPAPER_WHITE:      /* B -> N, W -> W (Current) */				pixels = 0x55 + ((pixels ^ 0xaa) >> 1);				break;			case REPAPER_INVERSE:    /* B -> N, W -> B (New) */				pixels = 0x55 | (pixels ^ 0xaa);				break;			case REPAPER_NORMAL:     /* B -> B, W -> W (New) */				pixels = 0xaa | (pixels >> 1);				break;			} 			pixels = (pixels & pixel_mask) | (~pixel_mask & 0x55);			p1 = (pixels >> 6) & 0x03;			p2 = (pixels >> 4) & 0x03;			p3 = (pixels >> 2) & 0x03;			p4 = (pixels >> 0) & 0x03;			pixels = (p1 << 0) | (p2 << 2) | (p3 << 4) | (p4 << 6);			*(*pp)++ = pixels;		} else {			*(*pp)++ = fixed_value;		}	}} /* pixels on display are numbered from 1 so odd is actually bits 0,2,4,... */static void repaper_odd_pixels(struct repaper_epd *epd, u8 **pp,			       const u8 *data, u8 fixed_value, const u8 *mask,			       enum repaper_stage stage){	unsigned int b; 	for (b = epd->width / 8; b > 0; b--) {		if (data) {			u8 pixels = data[b - 1] & 0x55;			u8 pixel_mask = 0xff; 			if (mask) {				pixel_mask = (mask[b - 1] ^ pixels) & 0x55;				pixel_mask |= pixel_mask << 1;			} 			switch (stage) {			case REPAPER_COMPENSATE: /* B -> W, W -> B (Current) */				pixels = 0xaa | (pixels ^ 0x55);				break;			case REPAPER_WHITE:      /* B -> N, W -> W (Current) */				pixels = 0x55 + (pixels ^ 0x55);				break;			case REPAPER_INVERSE:    /* B -> N, W -> B (New) */				pixels = 0x55 | ((pixels ^ 0x55) << 1);				break;			case REPAPER_NORMAL:     /* B -> B, W -> W (New) */				pixels = 0xaa | pixels;				break;			} 			pixels = (pixels & pixel_mask) | (~pixel_mask & 0x55);			*(*pp)++ = pixels;		} else {			*(*pp)++ = fixed_value;		}	}} /* interleave bits: (byte)76543210 -> (16 bit).7.6.5.4.3.2.1 */static inline u16 repaper_interleave_bits(u16 value){	value = (value | (value << 4)) & 0x0f0f;	value = (value | (value << 2)) & 0x3333;	value = (value | (value << 1)) & 0x5555; 	return value;} /* pixels on display are numbered from 1 */static void repaper_all_pixels(struct repaper_epd *epd, u8 **pp,			       const u8 *data, u8 fixed_value, const u8 *mask,			       enum repaper_stage stage){	unsigned int b; 	for (b = epd->width / 8; b > 0; b--) {		if (data) {			u16 pixels = repaper_interleave_bits(data[b - 1]);			u16 pixel_mask = 0xffff; 			if (mask) {				pixel_mask = repaper_interleave_bits(mask[b - 1]); 				pixel_mask = (pixel_mask ^ pixels) & 0x5555;				pixel_mask |= pixel_mask << 1;			} 			switch (stage) {			case REPAPER_COMPENSATE: /* B -> W, W -> B (Current) */				pixels = 0xaaaa | (pixels ^ 0x5555);				break;			case REPAPER_WHITE:      /* B -> N, W -> W (Current) */				pixels = 0x5555 + (pixels ^ 0x5555);				break;			case REPAPER_INVERSE:    /* B -> N, W -> B (New) */				pixels = 0x5555 | ((pixels ^ 0x5555) << 1);				break;			case REPAPER_NORMAL:     /* B -> B, W -> W (New) */				pixels = 0xaaaa | pixels;				break;			} 			pixels = (pixels & pixel_mask) | (~pixel_mask & 0x5555);			*(*pp)++ = pixels >> 8;			*(*pp)++ = pixels;		} else {			*(*pp)++ = fixed_value;			*(*pp)++ = fixed_value;		}	}} /* output one line of scan and data bytes to the display */static void repaper_one_line(struct repaper_epd *epd, unsigned int line,			     const u8 *data, u8 fixed_value, const u8 *mask,			     enum repaper_stage stage){	u8 *p = epd->line_buffer;	unsigned int b; 	repaper_spi_mosi_low(epd->spi); 	if (epd->pre_border_byte)		*p++ = 0x00; 	if (epd->middle_scan) {		/* data bytes */		repaper_odd_pixels(epd, &p, data, fixed_value, mask, stage); 		/* scan line */		for (b = epd->bytes_per_scan; b > 0; b--) {			if (line / 4 == b - 1)				*p++ = 0x03 << (2 * (line & 0x03));			else				*p++ = 0x00;		} 		/* data bytes */		repaper_even_pixels(epd, &p, data, fixed_value, mask, stage);	} else {		/*		 * even scan line, but as lines on display are numbered from 1,		 * line: 1,3,5,...		 */		for (b = 0; b < epd->bytes_per_scan; b++) {			if (0 != (line & 0x01) && line / 8 == b)				*p++ = 0xc0 >> (line & 0x06);			else				*p++ = 0x00;		} 		/* data bytes */		repaper_all_pixels(epd, &p, data, fixed_value, mask, stage); 		/*		 * odd scan line, but as lines on display are numbered from 1,		 * line: 0,2,4,6,...		 */		for (b = epd->bytes_per_scan; b > 0; b--) {			if (0 == (line & 0x01) && line / 8 == b - 1)				*p++ = 0x03 << (line & 0x06);			else				*p++ = 0x00;		}	} 	switch (epd->border_byte) {	case REPAPER_BORDER_BYTE_NONE:		break; 	case REPAPER_BORDER_BYTE_ZERO:		*p++ = 0x00;		break; 	case REPAPER_BORDER_BYTE_SET:		switch (stage) {		case REPAPER_COMPENSATE:		case REPAPER_WHITE:		case REPAPER_INVERSE:			*p++ = 0x00;			break;		case REPAPER_NORMAL:			*p++ = 0xaa;			break;		}		break;	} 	repaper_write_buf(epd->spi, 0x0a, epd->line_buffer,			  p - epd->line_buffer); 	/* Output data to panel */	repaper_write_val(epd->spi, 0x02, 0x07); 	repaper_spi_mosi_low(epd->spi);} static void repaper_frame_fixed(struct repaper_epd *epd, u8 fixed_value,				enum repaper_stage stage){	unsigned int line; 	for (line = 0; line < epd->height; line++)		repaper_one_line(epd, line, NULL, fixed_value, NULL, stage);} static void repaper_frame_data(struct repaper_epd *epd, const u8 *image,			       const u8 *mask, enum repaper_stage stage){	unsigned int line; 	if (!mask) {		for (line = 0; line < epd->height; line++) {			repaper_one_line(epd, line,					 &image[line * (epd->width / 8)],					 0, NULL, stage);		}	} else {		for (line = 0; line < epd->height; line++) {			size_t n = line * epd->width / 8; 			repaper_one_line(epd, line, &image[n], 0, &mask[n],					 stage);		}	}} static void repaper_frame_fixed_repeat(struct repaper_epd *epd, u8 fixed_value,				       enum repaper_stage stage){	u64 start = local_clock();	u64 end = start + (epd->factored_stage_time * 1000 * 1000); 	do {		repaper_frame_fixed(epd, fixed_value, stage);	} while (local_clock() < end);} static void repaper_frame_data_repeat(struct repaper_epd *epd, const u8 *image,				      const u8 *mask, enum repaper_stage stage){	u64 start = local_clock();	u64 end = start + (epd->factored_stage_time * 1000 * 1000); 	do {		repaper_frame_data(epd, image, mask, stage);	} while (local_clock() < end);} static void repaper_get_temperature(struct repaper_epd *epd){	int ret, temperature = 0;	unsigned int factor10x; 	if (!epd->thermal)		return; 	ret = thermal_zone_get_temp(epd->thermal, &temperature);	if (ret) {		DRM_DEV_ERROR(&epd->spi->dev, "Failed to get temperature (%d)\n", ret);		return;	} 	temperature /= 1000; 	if (temperature <= -10)		factor10x = 170;	else if (temperature <= -5)		factor10x = 120;	else if (temperature <= 5)		factor10x = 80;	else if (temperature <= 10)		factor10x = 40;

Lines 1–500 of 1155.