Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * DRM driver for PIXPAPER e-ink panel
4 *
5 * Author: LiangCheng Wang <zaq14760@gmail.com>,
6 */
7#include <linux/delay.h>
8#include <linux/module.h>
9#include <linux/spi/spi.h>
10
11#include <drm/clients/drm_client_setup.h>
12#include <drm/drm_atomic.h>
13#include <drm/drm_atomic_helper.h>
14#include <drm/drm_drv.h>
15#include <drm/drm_fbdev_shmem.h>
16#include <drm/drm_framebuffer.h>
17#include <drm/drm_gem_atomic_helper.h>
18#include <drm/drm_gem_shmem_helper.h>
19#include <drm/drm_gem_framebuffer_helper.h>
20#include <drm/drm_print.h>
21#include <drm/drm_probe_helper.h>
22
23/*
24 * Note on Undocumented Commands/Registers:
25 *
26 * Several commands and register parameters defined in this header are not
27 * documented in the datasheet. Their values and usage have been derived
28 * through analysis of existing userspace example programs.
29 *
30 * These 'unknown' definitions are crucial for the proper initialization
31 * and stable operation of the panel. Modifying these values without
32 * thorough understanding may lead to display anomalies, panel damage,
33 * or unexpected behavior.
34 */
35
36/* Command definitions */
37#define PIXPAPER_CMD_PANEL_SETTING 0x00 /* R00H: Panel settings */
38#define PIXPAPER_CMD_POWER_SETTING 0x01 /* R01H: Power settings */
39#define PIXPAPER_CMD_POWER_OFF 0x02 /* R02H: Power off */
40#define PIXPAPER_CMD_POWER_OFF_SEQUENCE 0x03 /* R03H: Power off sequence */
41#define PIXPAPER_CMD_POWER_ON 0x04 /* R04H: Power on */
42#define PIXPAPER_CMD_BOOSTER_SOFT_START 0x06 /* R06H: Booster soft start */
43#define PIXPAPER_CMD_DEEP_SLEEP 0x07 /* R07H: Deep sleep */
44#define PIXPAPER_CMD_DATA_START_TRANSMISSION 0x10
45/* R10H: Data transmission start */
46#define PIXPAPER_CMD_DISPLAY_REFRESH 0x12 /* R12H: Display refresh */
47#define PIXPAPER_CMD_PLL_CONTROL 0x30 /* R30H: PLL control */
48#define PIXPAPER_CMD_TEMP_SENSOR_CALIB 0x41
49/* R41H: Temperature sensor calibration */
50#define PIXPAPER_CMD_UNKNOWN_4D 0x4D /* R4DH: Unknown command */
51#define PIXPAPER_CMD_VCOM_INTERVAL 0x50 /* R50H: VCOM interval */
52#define PIXPAPER_CMD_UNKNOWN_60 0x60 /* R60H: Unknown command */
53#define PIXPAPER_CMD_RESOLUTION_SETTING 0x61 /* R61H: Resolution settings */
54#define PIXPAPER_CMD_GATE_SOURCE_START 0x65 /* R65H: Gate/source start */
55#define PIXPAPER_CMD_UNKNOWN_B4 0xB4 /* RB4H: Unknown command */
56#define PIXPAPER_CMD_UNKNOWN_B5 0xB5 /* RB5H: Unknown command */
57#define PIXPAPER_CMD_UNKNOWN_E0 0xE0 /* RE0H: Unknown command */
58#define PIXPAPER_CMD_POWER_SAVING 0xE3 /* RE3H: Power saving */
59#define PIXPAPER_CMD_UNKNOWN_E7 0xE7 /* RE7H: Unknown command */
60#define PIXPAPER_CMD_UNKNOWN_E9 0xE9 /* RE9H: Unknown command */
61
62/* R00H PSR - First Parameter */
63#define PIXPAPER_PSR_RST_N BIT(0)
64/* Bit 0: RST_N, 1=no effect (default), 0=reset with booster OFF */
65#define PIXPAPER_PSR_SHD_N BIT(1)
66/* Bit 1: SHD_N, 1=booster ON (default), 0=booster OFF */
67#define PIXPAPER_PSR_SHL BIT(2)
68/* Bit 2: SHL, 1=shift right (default), 0=shift left */
69#define PIXPAPER_PSR_UD BIT(3)
70/* Bit 3: UD, 1=scan up (default), 0=scan down */
71#define PIXPAPER_PSR_PST_MODE BIT(5)
72/* Bit 5: PST_MODE, 0=frame scanning (default), 1=external */
73#define PIXPAPER_PSR_RES_MASK (3 << 6)
74/* Bits 7-6: RES[1:0], resolution setting */
75#define PIXPAPER_PSR_RES_176x296 (0x0 << 6) /* 00: 176x296 */
76#define PIXPAPER_PSR_RES_128x296 (0x1 << 6) /* 01: 128x296 */
77#define PIXPAPER_PSR_RES_128x250 (0x2 << 6) /* 10: 128x250 */
78#define PIXPAPER_PSR_RES_112x204 (0x3 << 6) /* 11: 112x204 */
79#define PIXPAPER_PSR_CONFIG \
80 (PIXPAPER_PSR_RST_N | PIXPAPER_PSR_SHD_N | PIXPAPER_PSR_SHL | \
81 PIXPAPER_PSR_UD)
82/* 0x0F: Default settings, resolution set by R61H */
83
84/* R00H PSR - Second Parameter */
85#define PIXPAPER_PSR2_VC_LUTZ \
86 (1 << 0) /* Bit 0: VC_LUTZ, 1=VCOM float after refresh (default), 0=no effect */
87#define PIXPAPER_PSR2_NORG \
88 (1 << 1) /* Bit 1: NORG, 1=VCOM to GND before power off, 0=no effect (default) */
89#define PIXPAPER_PSR2_TIEG \
90 (1 << 2) /* Bit 2: TIEG, 1=VGN to GND on power off, 0=no effect (default) */
91#define PIXPAPER_PSR2_TS_AUTO \
92 (1 << 3) /* Bit 3: TS_AUTO, 1=sensor on RST_N low to high (default), 0=on booster */
93#define PIXPAPER_PSR2_VCMZ \
94 (1 << 4) /* Bit 4: VCMZ, 1=VCOM always floating, 0=no effect (default) */
95#define PIXPAPER_PSR2_FOPT \
96 (1 << 5) /* Bit 5: FOPT, 0=scan 1 frame (default), 1=no scan, HiZ */
97#define PIXPAPER_PSR_CONFIG2 \
98 (PIXPAPER_PSR2_VC_LUTZ | \
99 PIXPAPER_PSR2_TS_AUTO) /* 0x09: Default VCOM and temp sensor settings */
100
101/* R01H PWR - Power Setting Register */
102/* First Parameter */
103#define PIXPAPER_PWR_VDG_EN \
104 (1 << 0) /* Bit 0: VDG_EN, 1=internal DCDC for VGP/VGN (default), 0=external */
105#define PIXPAPER_PWR_VDS_EN \
106 (1 << 1) /* Bit 1: VDS_EN, 1=internal regulator for VSP/VSN (default), 0=external */
107#define PIXPAPER_PWR_VSC_EN \
108 (1 << 2) /* Bit 2: VSC_EN, 1=internal regulator for VSPL (default), 0=external */
109#define PIXPAPER_PWR_V_MODE \
110 (1 << 3) /* Bit 3: V_MODE, 0=Mode0 (default), 1=Mode1 */
111#define PIXPAPER_PWR_CONFIG1 \
112 (PIXPAPER_PWR_VDG_EN | PIXPAPER_PWR_VDS_EN | \
113 PIXPAPER_PWR_VSC_EN) /* 0x07: Internal power for VGP/VGN, VSP/VSN, VSPL */
114
115/* Second Parameter */
116#define PIXPAPER_PWR_VGPN_MASK \
117 (3 << 0) /* Bits 1-0: VGPN, VGP/VGN voltage levels */
118#define PIXPAPER_PWR_VGPN_20V (0x0 << 0) /* 00: VGP=20V, VGN=-20V (default) */
119#define PIXPAPER_PWR_VGPN_17V (0x1 << 0) /* 01: VGP=17V, VGN=-17V */
120#define PIXPAPER_PWR_VGPN_15V (0x2 << 0) /* 10: VGP=15V, VGN=-15V */
121#define PIXPAPER_PWR_VGPN_10V (0x3 << 0) /* 11: VGP=10V, VGN=-10V */
122#define PIXPAPER_PWR_CONFIG2 PIXPAPER_PWR_VGPN_20V /* 0x00: VGP=20V, VGN=-20V */
123
124/* Third, Fourth, Sixth Parameters (VSP_1, VSPL_0, VSPL_1) */
125#define PIXPAPER_PWR_VSP_8_2V 0x22 /* VSP_1/VSPL_1: 8.2V (34 decimal) */
126#define PIXPAPER_PWR_VSPL_15V 0x78 /* VSPL_0: 15V (120 decimal) */
127
128/* Fifth Parameter (VSN_1) */
129#define PIXPAPER_PWR_VSN_4V 0x0A /* VSN_1: -4V (10 decimal) */
130
131/* R03H PFS - Power Off Sequence Setting Register */
132/* First Parameter */
133#define PIXPAPER_PFS_T_VDS_OFF_MASK \
134 (3 << 0) /* Bits 1-0: T_VDS_OFF, VSP/VSN power-off sequence */
135#define PIXPAPER_PFS_T_VDS_OFF_20MS (0x0 << 0) /* 00: 20 ms (default) */
136#define PIXPAPER_PFS_T_VDS_OFF_40MS (0x1 << 0) /* 01: 40 ms */
137#define PIXPAPER_PFS_T_VDS_OFF_60MS (0x2 << 0) /* 10: 60 ms */
138#define PIXPAPER_PFS_T_VDS_OFF_80MS (0x3 << 0) /* 11: 80 ms */
139#define PIXPAPER_PFS_T_VDPG_OFF_MASK \
140 (3 << 4) /* Bits 5-4: T_VDPG_OFF, VGP/VGN power-off sequence */
141#define PIXPAPER_PFS_T_VDPG_OFF_20MS (0x0 << 4) /* 00: 20 ms (default) */
142#define PIXPAPER_PFS_T_VDPG_OFF_40MS (0x1 << 4) /* 01: 40 ms */
143#define PIXPAPER_PFS_T_VDPG_OFF_60MS (0x2 << 4) /* 10: 60 ms */
144#define PIXPAPER_PFS_T_VDPG_OFF_80MS (0x3 << 4) /* 11: 80 ms */
145#define PIXPAPER_PFS_CONFIG1 \
146 (PIXPAPER_PFS_T_VDS_OFF_20MS | \
147 PIXPAPER_PFS_T_VDPG_OFF_20MS) /* 0x10: Default 20 ms for VSP/VSN and VGP/VGN */
148
149/* Second Parameter */
150#define PIXPAPER_PFS_VGP_EXT_MASK \
151 (0xF << 0) /* Bits 3-0: VGP_EXT, VGP extension time */
152#define PIXPAPER_PFS_VGP_EXT_0MS (0x0 << 0) /* 0000: 0 ms */
153#define PIXPAPER_PFS_VGP_EXT_500MS (0x1 << 0) /* 0001: 500 ms */
154#define PIXPAPER_PFS_VGP_EXT_1000MS (0x2 << 0) /* 0010: 1000 ms */
155#define PIXPAPER_PFS_VGP_EXT_1500MS (0x3 << 0) /* 0011: 1500 ms */
156#define PIXPAPER_PFS_VGP_EXT_2000MS (0x4 << 0) /* 0100: 2000 ms (default) */
157#define PIXPAPER_PFS_VGP_EXT_2500MS (0x5 << 0) /* 0101: 2500 ms */
158#define PIXPAPER_PFS_VGP_EXT_3000MS (0x6 << 0) /* 0110: 3000 ms */
159#define PIXPAPER_PFS_VGP_EXT_3500MS (0x7 << 0) /* 0111: 3500 ms */
160#define PIXPAPER_PFS_VGP_EXT_4000MS (0x8 << 0) /* 1000: 4000 ms */
161#define PIXPAPER_PFS_VGP_EXT_4500MS (0x9 << 0) /* 1001: 4500 ms */
162#define PIXPAPER_PFS_VGP_EXT_5000MS (0xA << 0) /* 1010: 5000 ms */
163#define PIXPAPER_PFS_VGP_EXT_5500MS (0xB << 0) /* 1011: 5500 ms */
164#define PIXPAPER_PFS_VGP_EXT_6000MS (0xC << 0) /* 1100: 6000 ms */
165#define PIXPAPER_PFS_VGP_EXT_6500MS (0xD << 0) /* 1101: 6500 ms */
166#define PIXPAPER_PFS_VGP_LEN_MASK \
167 (0xF << 4) /* Bits 7-4: VGP_LEN, VGP at 10V during power-off */
168#define PIXPAPER_PFS_VGP_LEN_0MS (0x0 << 4) /* 0000: 0 ms */
169#define PIXPAPER_PFS_VGP_LEN_500MS (0x1 << 4) /* 0001: 500 ms */
170#define PIXPAPER_PFS_VGP_LEN_1000MS (0x2 << 4) /* 0010: 1000 ms */
171#define PIXPAPER_PFS_VGP_LEN_1500MS (0x3 << 4) /* 0011: 1500 ms */
172#define PIXPAPER_PFS_VGP_LEN_2000MS (0x4 << 4) /* 0100: 2000 ms */
173#define PIXPAPER_PFS_VGP_LEN_2500MS (0x5 << 4) /* 0101: 2500 ms (default) */
174#define PIXPAPER_PFS_VGP_LEN_3000MS (0x6 << 4) /* 0110: 3000 ms */
175#define PIXPAPER_PFS_VGP_LEN_3500MS (0x7 << 4) /* 0111: 3500 ms */
176#define PIXPAPER_PFS_VGP_LEN_4000MS (0x8 << 4) /* 1000: 4000 ms */
177#define PIXPAPER_PFS_VGP_LEN_4500MS (0x9 << 4) /* 1001: 4500 ms */
178#define PIXPAPER_PFS_VGP_LEN_5000MS (0xA << 4) /* 1010: 5000 ms */
179#define PIXPAPER_PFS_VGP_LEN_5500MS (0xB << 4) /* 1011: 5500 ms */
180#define PIXPAPER_PFS_VGP_LEN_6000MS (0xC << 4) /* 1100: 6000 ms */
181#define PIXPAPER_PFS_VGP_LEN_6500MS (0xD << 4) /* 1101: 6500 ms */
182#define PIXPAPER_PFS_CONFIG2 \
183 (PIXPAPER_PFS_VGP_EXT_1000MS | \
184 PIXPAPER_PFS_VGP_LEN_2500MS) /* 0x54: VGP extension 1000 ms, VGP at 10V for 2500 ms */
185
186/* Third Parameter */
187#define PIXPAPER_PFS_XON_LEN_MASK \
188 (0xF << 0) /* Bits 3-0: XON_LEN, XON enable time */
189#define PIXPAPER_PFS_XON_LEN_0MS (0x0 << 0) /* 0000: 0 ms */
190#define PIXPAPER_PFS_XON_LEN_500MS (0x1 << 0) /* 0001: 500 ms */
191#define PIXPAPER_PFS_XON_LEN_1000MS (0x2 << 0) /* 0010: 1000 ms */
192#define PIXPAPER_PFS_XON_LEN_1500MS (0x3 << 0) /* 0011: 1500 ms */
193#define PIXPAPER_PFS_XON_LEN_2000MS (0x4 << 0) /* 0100: 2000 ms (default) */
194#define PIXPAPER_PFS_XON_LEN_2500MS (0x5 << 0) /* 0101: 2500 ms */
195#define PIXPAPER_PFS_XON_LEN_3000MS (0x6 << 0) /* 0110: 3000 ms */
196#define PIXPAPER_PFS_XON_LEN_3500MS (0x7 << 0) /* 0111: 3500 ms */
197#define PIXPAPER_PFS_XON_LEN_4000MS (0x8 << 0) /* 1000: 4000 ms */
198#define PIXPAPER_PFS_XON_LEN_4500MS (0x9 << 0) /* 1001: 4500 ms */
199#define PIXPAPER_PFS_XON_LEN_5000MS (0xA << 0) /* 1010: 5000 ms */
200#define PIXPAPER_PFS_XON_LEN_5500MS (0xB << 0) /* 1011: 5500 ms */
201#define PIXPAPER_PFS_XON_LEN_6000MS (0xC << 0) /* 1100: 6000 ms */
202#define PIXPAPER_PFS_XON_DLY_MASK \
203 (0xF << 4) /* Bits 7-4: XON_DLY, XON delay time */
204#define PIXPAPER_PFS_XON_DLY_0MS (0x0 << 4) /* 0000: 0 ms */
205#define PIXPAPER_PFS_XON_DLY_500MS (0x1 << 4) /* 0001: 500 ms */
206#define PIXPAPER_PFS_XON_DLY_1000MS (0x2 << 4) /* 0010: 1000 ms */
207#define PIXPAPER_PFS_XON_DLY_1500MS (0x3 << 4) /* 0011: 1500 ms */
208#define PIXPAPER_PFS_XON_DLY_2000MS (0x4 << 4) /* 0100: 2000 ms (default) */
209#define PIXPAPER_PFS_XON_DLY_2500MS (0x5 << 4) /* 0101: 2500 ms */
210#define PIXPAPER_PFS_XON_DLY_3000MS (0x6 << 4) /* 0110: 3000 ms */
211#define PIXPAPER_PFS_XON_DLY_3500MS (0x7 << 4) /* 0111: 3500 ms */
212#define PIXPAPER_PFS_XON_DLY_4000MS (0x8 << 4) /* 1000: 4000 ms */
213#define PIXPAPER_PFS_XON_DLY_4500MS (0x9 << 4) /* 1001: 4500 ms */
214#define PIXPAPER_PFS_XON_DLY_5000MS (0xA << 4) /* 1010: 5000 ms */
215#define PIXPAPER_PFS_XON_DLY_5500MS (0xB << 4) /* 1011: 5500 ms */
216#define PIXPAPER_PFS_XON_DLY_6000MS (0xC << 4) /* 1100: 6000 ms */
217#define PIXPAPER_PFS_CONFIG3 \
218 (PIXPAPER_PFS_XON_LEN_2000MS | \
219 PIXPAPER_PFS_XON_DLY_2000MS) /* 0x44: XON enable and delay at 2000 ms */
220
221/* R06H BTST - Booster Soft Start Command */
222/* First Parameter */
223#define PIXPAPER_BTST_PHA_SFT_MASK \
224 (3 << 0) /* Bits 1-0: PHA_SFT, soft start period for phase A */
225#define PIXPAPER_BTST_PHA_SFT_10MS (0x0 << 0) /* 00: 10 ms (default) */
226#define PIXPAPER_BTST_PHA_SFT_20MS (0x1 << 0) /* 01: 20 ms */
227#define PIXPAPER_BTST_PHA_SFT_30MS (0x2 << 0) /* 10: 30 ms */
228#define PIXPAPER_BTST_PHA_SFT_40MS (0x3 << 0) /* 11: 40 ms */
229#define PIXPAPER_BTST_PHB_SFT_MASK \
230 (3 << 2) /* Bits 3-2: PHB_SFT, soft start period for phase B */
231#define PIXPAPER_BTST_PHB_SFT_10MS (0x0 << 2) /* 00: 10 ms (default) */
232#define PIXPAPER_BTST_PHB_SFT_20MS (0x1 << 2) /* 01: 20 ms */
233#define PIXPAPER_BTST_PHB_SFT_30MS (0x2 << 2) /* 10: 30 ms */
234#define PIXPAPER_BTST_PHB_SFT_40MS (0x3 << 2) /* 11: 40 ms */
235#define PIXPAPER_BTST_CONFIG1 \
236 (PIXPAPER_BTST_PHA_SFT_40MS | \
237 PIXPAPER_BTST_PHB_SFT_40MS) /* 0x0F: 40 ms for phase A and B */
238
239/* Second to Seventh Parameters (Driving Strength or Minimum OFF Time) */
240#define PIXPAPER_BTST_CONFIG2 0x0A /* Strength11 */
241#define PIXPAPER_BTST_CONFIG3 0x2F /* Period48 */
242#define PIXPAPER_BTST_CONFIG4 0x25 /* Strength38 */
243#define PIXPAPER_BTST_CONFIG5 0x22 /* Period35 */
244#define PIXPAPER_BTST_CONFIG6 0x2E /* Strength47 */
245#define PIXPAPER_BTST_CONFIG7 0x21 /* Period34 */
246
247/* R12H: DRF (Display Refresh) */
248#define PIXPAPER_DRF_VCOM_AC 0x00 /* AC VCOM: VCOM follows LUTC (default) */
249#define PIXPAPER_DRF_VCOM_DC 0x01 /* DC VCOM: VCOM fixed to VCOMDC */
250
251/* R30H PLL - PLL Control Register */
252/* First Parameter */
253#define PIXPAPER_PLL_FR_MASK (0x7 << 0) /* Bits 2-0: FR, frame rate */
254#define PIXPAPER_PLL_FR_12_5HZ (0x0 << 0) /* 000: 12.5 Hz */
255#define PIXPAPER_PLL_FR_25HZ (0x1 << 0) /* 001: 25 Hz */
256#define PIXPAPER_PLL_FR_50HZ (0x2 << 0) /* 010: 50 Hz (default) */
257#define PIXPAPER_PLL_FR_65HZ (0x3 << 0) /* 011: 65 Hz */
258#define PIXPAPER_PLL_FR_75HZ (0x4 << 0) /* 100: 75 Hz */
259#define PIXPAPER_PLL_FR_85HZ (0x5 << 0) /* 101: 85 Hz */
260#define PIXPAPER_PLL_FR_100HZ (0x6 << 0) /* 110: 100 Hz */
261#define PIXPAPER_PLL_FR_120HZ (0x7 << 0) /* 111: 120 Hz */
262#define PIXPAPER_PLL_DFR \
263 (1 << 3) /* Bit 3: Dynamic frame rate, 0=disabled (default), 1=enabled */
264#define PIXPAPER_PLL_CONFIG \
265 (PIXPAPER_PLL_FR_50HZ) /* 0x02: 50 Hz, dynamic frame rate disabled */
266
267/* R41H TSE - Temperature Sensor Calibration Register */
268/* First Parameter */
269#define PIXPAPER_TSE_TO_MASK \
270 (0xF << 0) /* Bits 3-0: TO[3:0], temperature offset */
271#define PIXPAPER_TSE_TO_POS_0C (0x0 << 0) /* 0000: +0°C (default) */
272#define PIXPAPER_TSE_TO_POS_0_5C (0x1 << 0) /* 0001: +0.5°C */
273#define PIXPAPER_TSE_TO_POS_1C (0x2 << 0) /* 0010: +1°C */
274#define PIXPAPER_TSE_TO_POS_1_5C (0x3 << 0) /* 0011: +1.5°C */
275#define PIXPAPER_TSE_TO_POS_2C (0x4 << 0) /* 0100: +2°C */
276#define PIXPAPER_TSE_TO_POS_2_5C (0x5 << 0) /* 0101: +2.5°C */
277#define PIXPAPER_TSE_TO_POS_3C (0x6 << 0) /* 0110: +3°C */
278#define PIXPAPER_TSE_TO_POS_3_5C (0x7 << 0) /* 0111: +3.5°C */
279#define PIXPAPER_TSE_TO_NEG_4C (0x8 << 0) /* 1000: -4°C */
280#define PIXPAPER_TSE_TO_NEG_3_5C (0x9 << 0) /* 1001: -3.5°C */
281#define PIXPAPER_TSE_TO_NEG_3C (0xA << 0) /* 1010: -3°C */
282#define PIXPAPER_TSE_TO_NEG_2_5C (0xB << 0) /* 1011: -2.5°C */
283#define PIXPAPER_TSE_TO_NEG_2C (0xC << 0) /* 1100: -2°C */
284#define PIXPAPER_TSE_TO_NEG_1_5C (0xD << 0) /* 1101: -1.5°C */
285#define PIXPAPER_TSE_TO_NEG_1C (0xE << 0) /* 1110: -1°C */
286#define PIXPAPER_TSE_TO_NEG_0_5C (0xF << 0) /* 1111: -0.5°C */
287#define PIXPAPER_TSE_TO_FINE_MASK \
288 (0x3 << 4) /* Bits 5-4: TO[5:4], fine adjustment for positive offsets */
289#define PIXPAPER_TSE_TO_FINE_0C (0x0 << 4) /* 00: +0.0°C (default) */
290#define PIXPAPER_TSE_TO_FINE_0_25C (0x1 << 4) /* 01: +0.25°C */
291#define PIXPAPER_TSE_ENABLE \
292 (0 << 7) /* Bit 7: TSE, 0=internal sensor enabled (default), 1=disabled (external) */
293#define PIXPAPER_TSE_DISABLE \
294 (1 << 7) /* Bit 7: TSE, 1=internal sensor disabled, use external */
295#define PIXPAPER_TSE_CONFIG \
296 (PIXPAPER_TSE_TO_POS_0C | PIXPAPER_TSE_TO_FINE_0C | \
297 PIXPAPER_TSE_ENABLE) /* 0x00: Internal sensor enabled, +0°C offset */
298
299/* R4DH */
300#define PIXPAPER_UNKNOWN_4D_CONFIG \
301 0x78 /* This value is essential for initialization, derived from userspace examples. */
302
303/* R50H CDI - VCOM and DATA Interval Setting Register */
304/* First Parameter */
305#define PIXPAPER_CDI_INTERVAL_MASK \
306 (0xF << 0) /* Bits 3-0: CDI[3:0], VCOM and data interval (hsync) */
307#define PIXPAPER_CDI_17_HSYNC (0x0 << 0) /* 0000: 17 hsync */
308#define PIXPAPER_CDI_16_HSYNC (0x1 << 0) /* 0001: 16 hsync */
309#define PIXPAPER_CDI_15_HSYNC (0x2 << 0) /* 0010: 15 hsync */
310#define PIXPAPER_CDI_14_HSYNC (0x3 << 0) /* 0011: 14 hsync */
311#define PIXPAPER_CDI_13_HSYNC (0x4 << 0) /* 0100: 13 hsync */
312#define PIXPAPER_CDI_12_HSYNC (0x5 << 0) /* 0101: 12 hsync */
313#define PIXPAPER_CDI_11_HSYNC (0x6 << 0) /* 0110: 11 hsync */
314#define PIXPAPER_CDI_10_HSYNC (0x7 << 0) /* 0111: 10 hsync (default) */
315#define PIXPAPER_CDI_9_HSYNC (0x8 << 0) /* 1000: 9 hsync */
316#define PIXPAPER_CDI_8_HSYNC (0x9 << 0) /* 1001: 8 hsync */
317#define PIXPAPER_CDI_7_HSYNC (0xA << 0) /* 1010: 7 hsync */
318#define PIXPAPER_CDI_6_HSYNC (0xB << 0) /* 1011: 6 hsync */
319#define PIXPAPER_CDI_5_HSYNC (0xC << 0) /* 1100: 5 hsync */
320#define PIXPAPER_CDI_4_HSYNC (0xD << 0) /* 1101: 4 hsync */
321#define PIXPAPER_CDI_3_HSYNC (0xE << 0) /* 1110: 3 hsync */
322#define PIXPAPER_CDI_2_HSYNC (0xF << 0) /* 1111: 2 hsync */
323#define PIXPAPER_CDI_DDX \
324 (1 << 4) /* Bit 4: DDX, 0=grayscale mapping 0, 1=grayscale mapping 1 (default) */
325#define PIXPAPER_CDI_VBD_MASK \
326 (0x7 << 5) /* Bits 7-5: VBD[2:0], border data selection */
327#define PIXPAPER_CDI_VBD_FLOAT (0x0 << 5) /* 000: Floating (DDX=0 or 1) */
328#define PIXPAPER_CDI_VBD_GRAY3_DDX0 \
329 (0x1 << 5) /* 001: Gray3 (border_buf=011) when DDX=0 */
330#define PIXPAPER_CDI_VBD_GRAY2_DDX0 \
331 (0x2 << 5) /* 010: Gray2 (border_buf=010) when DDX=0 */
332#define PIXPAPER_CDI_VBD_GRAY1_DDX0 \
333 (0x3 << 5) /* 011: Gray1 (border_buf=001) when DDX=0 */
334#define PIXPAPER_CDI_VBD_GRAY0_DDX0 \
335 (0x4 << 5) /* 100: Gray0 (border_buf=000) when DDX=0 */
336#define PIXPAPER_CDI_VBD_GRAY0_DDX1 \
337 (0x0 << 5) /* 000: Gray0 (border_buf=000) when DDX=1 */
338#define PIXPAPER_CDI_VBD_GRAY1_DDX1 \
339 (0x1 << 5) /* 001: Gray1 (border_buf=001) when DDX=1 */
340#define PIXPAPER_CDI_VBD_GRAY2_DDX1 \
341 (0x2 << 5) /* 010: Gray2 (border_buf=010) when DDX=1 */
342#define PIXPAPER_CDI_VBD_GRAY3_DDX1 \
343 (0x3 << 5) /* 011: Gray3 (border_buf=011) when DDX=1 */
344#define PIXPAPER_CDI_VBD_FLOAT_DDX1 (0x4 << 5) /* 100: Floating when DDX=1 */
345#define PIXPAPER_CDI_CONFIG \
346 (PIXPAPER_CDI_10_HSYNC | PIXPAPER_CDI_DDX | \
347 PIXPAPER_CDI_VBD_GRAY1_DDX1) /* 0x37: 10 hsync, DDX=1, border Gray1 */
348
349/* R60H */
350#define PIXPAPER_UNKNOWN_60_CONFIG1 \
351 0x02 /* This value is essential for initialization, derived from userspace examples. */
352#define PIXPAPER_UNKNOWN_60_CONFIG2 \
353 0x02 /* This value is essential for initialization, derived from userspace examples. */
354
355/* R61H TRES - Resolution Setting Register */
356#define PIXPAPER_TRES_HRES_H \
357 ((PIXPAPER_PANEL_BUFFER_WIDTH >> 8) & \
358 0xFF) /* HRES[9:8]: High byte of horizontal resolution (128) */
359#define PIXPAPER_TRES_HRES_L \
360 (PIXPAPER_PANEL_BUFFER_WIDTH & \
361 0xFF) /* HRES[7:0]: Low byte of horizontal resolution (128 = 0x80) */
362#define PIXPAPER_TRES_VRES_H \
363 ((PIXPAPER_HEIGHT >> 8) & \
364 0xFF) /* VRES[9:8]: High byte of vertical resolution (250) */
365#define PIXPAPER_TRES_VRES_L \
366 (PIXPAPER_HEIGHT & \
367 0xFF) /* VRES[7:0]: Low byte of vertical resolution (250 = 0xFA) */
368
369/* R65H GSST - Gate/Source Start Setting Register */
370#define PIXPAPER_GSST_S_START 0x00 /* S_Start[7:0]: First source line (S0) */
371#define PIXPAPER_GSST_RESERVED 0x00 /* Reserved byte */
372#define PIXPAPER_GSST_G_START_H \
373 0x00 /* G_Start[8]: High bit of first gate line (G0) */
374#define PIXPAPER_GSST_G_START_L \
375 0x00 /* G_Start[7:0]: Low byte of first gate line (G0) */
376
377/* RB4H */
378#define PIXPAPER_UNKNOWN_B4_CONFIG \
379 0xD0 /* This value is essential for initialization, derived from userspace examples. */
380
381/* RB5H */
382#define PIXPAPER_UNKNOWN_B5_CONFIG \
383 0x03 /* This value is essential for initialization, derived from userspace examples. */
384
385/* RE0H */
386#define PIXPAPER_UNKNOWN_E0_CONFIG \
387 0x00 /* This value is essential for initialization, derived from userspace examples. */
388
389/* RE3H PWS - Power Saving Register */
390/* First Parameter */
391#define PIXPAPER_PWS_VCOM_W_MASK \
392 (0xF \
393 << 4) /* Bits 7-4: VCOM_W[3:0], VCOM power-saving width (line periods) */
394#define PIXPAPER_PWS_VCOM_W_0 (0x0 << 4) /* 0000: 0 line periods */
395#define PIXPAPER_PWS_VCOM_W_1 (0x1 << 4) /* 0001: 1 line period */
396#define PIXPAPER_PWS_VCOM_W_2 (0x2 << 4) /* 0010: 2 line periods */
397#define PIXPAPER_PWS_VCOM_W_3 (0x3 << 4) /* 0011: 3 line periods */
398#define PIXPAPER_PWS_VCOM_W_4 (0x4 << 4) /* 0100: 4 line periods */
399#define PIXPAPER_PWS_VCOM_W_5 (0x5 << 4) /* 0101: 5 line periods */
400#define PIXPAPER_PWS_VCOM_W_6 (0x6 << 4) /* 0110: 6 line periods */
401#define PIXPAPER_PWS_VCOM_W_7 (0x7 << 4) /* 0111: 7 line periods */
402#define PIXPAPER_PWS_VCOM_W_8 (0x8 << 4) /* 1000: 8 line periods */
403#define PIXPAPER_PWS_VCOM_W_9 (0x9 << 4) /* 1001: 9 line periods */
404#define PIXPAPER_PWS_VCOM_W_10 (0xA << 4) /* 1010: 10 line periods */
405#define PIXPAPER_PWS_VCOM_W_11 (0xB << 4) /* 1011: 11 line periods */
406#define PIXPAPER_PWS_VCOM_W_12 (0xC << 4) /* 1100: 12 line periods */
407#define PIXPAPER_PWS_VCOM_W_13 (0xD << 4) /* 1101: 13 line periods */
408#define PIXPAPER_PWS_VCOM_W_14 (0xE << 4) /* 1110: 14 line periods */
409#define PIXPAPER_PWS_VCOM_W_15 (0xF << 4) /* 1111: 15 line periods */
410#define PIXPAPER_PWS_SD_W_MASK \
411 (0xF << 0) /* Bits 3-0: SD_W[3:0], source power-saving width (660 ns units) */
412#define PIXPAPER_PWS_SD_W_0 (0x0 << 0) /* 0000: 0 ns */
413#define PIXPAPER_PWS_SD_W_1 (0x1 << 0) /* 0001: 660 ns */
414#define PIXPAPER_PWS_SD_W_2 (0x2 << 0) /* 0010: 1320 ns */
415#define PIXPAPER_PWS_SD_W_3 (0x3 << 0) /* 0011: 1980 ns */
416#define PIXPAPER_PWS_SD_W_4 (0x4 << 0) /* 0100: 2640 ns */
417#define PIXPAPER_PWS_SD_W_5 (0x5 << 0) /* 0101: 3300 ns */
418#define PIXPAPER_PWS_SD_W_6 (0x6 << 0) /* 0110: 3960 ns */
419#define PIXPAPER_PWS_SD_W_7 (0x7 << 0) /* 0111: 4620 ns */
420#define PIXPAPER_PWS_SD_W_8 (0x8 << 0) /* 1000: 5280 ns */
421#define PIXPAPER_PWS_SD_W_9 (0x9 << 0) /* 1001: 5940 ns */
422#define PIXPAPER_PWS_SD_W_10 (0xA << 0) /* 1010: 6600 ns */
423#define PIXPAPER_PWS_SD_W_11 (0xB << 0) /* 1011: 7260 ns */
424#define PIXPAPER_PWS_SD_W_12 (0xC << 0) /* 1100: 7920 ns */
425#define PIXPAPER_PWS_SD_W_13 (0xD << 0) /* 1101: 8580 ns */
426#define PIXPAPER_PWS_SD_W_14 (0xE << 0) /* 1110: 9240 ns */
427#define PIXPAPER_PWS_SD_W_15 (0xF << 0) /* 1111: 9900 ns */
428#define PIXPAPER_PWS_CONFIG \
429 (PIXPAPER_PWS_VCOM_W_2 | \
430 PIXPAPER_PWS_SD_W_2) /* 0x22: VCOM 2 line periods (160 µs), source 1320 ns */
431
432/* RE7H */
433#define PIXPAPER_UNKNOWN_E7_CONFIG \
434 0x1C /* This value is essential for initialization, derived from userspace examples. */
435
436/* RE9H */
437#define PIXPAPER_UNKNOWN_E9_CONFIG \
438 0x01 /* This value is essential for initialization, derived from userspace examples. */
439
440MODULE_IMPORT_NS("DMA_BUF");
441
442/*
443 * The panel has a visible resolution of 122x250.
444 * However, the controller requires the horizontal resolution to be aligned to 128 pixels.
445 * No porch or sync timing values are provided in the datasheet, so we define minimal
446 * placeholder values to satisfy the DRM framework.
447 */
448
449/* Panel visible resolution */
450#define PIXPAPER_WIDTH 122
451#define PIXPAPER_HEIGHT 250
452
453/* Controller requires 128 horizontal pixels total (for memory alignment) */
454#define PIXPAPER_HTOTAL 128
455#define PIXPAPER_HFP 2
456#define PIXPAPER_HSYNC 2
457#define PIXPAPER_HBP (PIXPAPER_HTOTAL - PIXPAPER_WIDTH - PIXPAPER_HFP - PIXPAPER_HSYNC)
458
459/*
460 * According to the datasheet, the total vertical blanking must be 55 lines,
461 * regardless of how the vertical back porch is set.
462 * Here we allocate VFP=2, VSYNC=2, and VBP=51 to sum up to 55 lines.
463 * Total vertical lines = 250 (visible) + 55 (blanking) = 305.
464 */
465#define PIXPAPER_VTOTAL (250 + 55)
466#define PIXPAPER_VFP 2
467#define PIXPAPER_VSYNC 2
468#define PIXPAPER_VBP (55 - PIXPAPER_VFP - PIXPAPER_VSYNC)
469
470/*
471 * Pixel clock calculation:
472 * pixel_clock = htotal * vtotal * refresh_rate
473 * = 128 * 305 * 50
474 * = 1,952,000 Hz = 1952 kHz
475 */
476#define PIXPAPER_PIXEL_CLOCK 1952
477
478#define PIXPAPER_WIDTH_MM 24 /* approximate from 23.7046mm */
479#define PIXPAPER_HEIGHT_MM 49 /* approximate from 48.55mm */
480
481#define PIXPAPER_SPI_BITS_PER_WORD 8
482#define PIXPAPER_SPI_SPEED_DEFAULT 1000000
483
484#define PIXPAPER_PANEL_BUFFER_WIDTH 128
485#define PIXPAPER_PANEL_BUFFER_TWO_BYTES_PER_ROW (PIXPAPER_PANEL_BUFFER_WIDTH / 4)
486
487#define PIXPAPER_COLOR_THRESHOLD_LOW_CHANNEL 60
488#define PIXPAPER_COLOR_THRESHOLD_HIGH_CHANNEL 200
489#define PIXPAPER_COLOR_THRESHOLD_YELLOW_MIN_GREEN 180
490
491struct pixpaper_error_ctx {
492 int errno_code;
493};
494
495struct pixpaper_panel {
496 struct drm_device drm;
497 struct drm_plane plane;
498 struct drm_crtc crtc;
499 struct drm_encoder encoder;
500 struct drm_connector connector;
501
502 struct spi_device *spi;
503 struct gpio_desc *reset;
504 struct gpio_desc *busy;
505 struct gpio_desc *dc;
506};
507
508static inline struct pixpaper_panel *to_pixpaper_panel(struct drm_device *drm)
509{
510 return container_of(drm, struct pixpaper_panel, drm);
511}
512
513static void pixpaper_wait_for_panel(struct pixpaper_panel *panel)
514{
515 unsigned int timeout_ms = 10000;
516 unsigned long timeout_jiffies = jiffies + msecs_to_jiffies(timeout_ms);
517
518 usleep_range(1000, 1500);
519 while (gpiod_get_value_cansleep(panel->busy) != 1) {
520 if (time_after(jiffies, timeout_jiffies)) {
521 drm_warn(&panel->drm, "Busy wait timed out\n");
522 return;
523 }
524 usleep_range(100, 200);
525 }
526}
527
528static void pixpaper_spi_sync(struct spi_device *spi, struct spi_message *msg,
529 struct pixpaper_error_ctx *err)
530{
531 if (err->errno_code)
532 return;
533
534 int ret = spi_sync(spi, msg);
535
536 if (ret < 0)
537 err->errno_code = ret;
538}
539
540static void pixpaper_send_cmd(struct pixpaper_panel *panel, u8 cmd,
541 struct pixpaper_error_ctx *err)
542{
543 if (err->errno_code)
544 return;
545
546 struct spi_transfer xfer = {
547 .tx_buf = &cmd,
548 .len = 1,
549 };
550 struct spi_message msg;
551
552 spi_message_init(&msg);
553 spi_message_add_tail(&xfer, &msg);
554
555 gpiod_set_value_cansleep(panel->dc, 0);
556 usleep_range(1, 5);
557 pixpaper_spi_sync(panel->spi, &msg, err);
558}
559
560static void pixpaper_send_data(struct pixpaper_panel *panel, u8 data,
561 struct pixpaper_error_ctx *err)
562{
563 if (err->errno_code)
564 return;
565
566 struct spi_transfer xfer = {
567 .tx_buf = &data,
568 .len = 1,
569 };
570 struct spi_message msg;
571
572 spi_message_init(&msg);
573 spi_message_add_tail(&xfer, &msg);
574
575 gpiod_set_value_cansleep(panel->dc, 1);
576 usleep_range(1, 5);
577 pixpaper_spi_sync(panel->spi, &msg, err);
578}
579
580static int pixpaper_panel_hw_init(struct pixpaper_panel *panel)
581{
582 struct pixpaper_error_ctx err = { .errno_code = 0 };
583
584 gpiod_set_value_cansleep(panel->reset, 0);
585 msleep(50);
586 gpiod_set_value_cansleep(panel->reset, 1);
587 msleep(50);
588
589 pixpaper_wait_for_panel(panel);
590
591 pixpaper_send_cmd(panel, PIXPAPER_CMD_UNKNOWN_4D, &err);
592 pixpaper_send_data(panel, PIXPAPER_UNKNOWN_4D_CONFIG, &err);
593 if (err.errno_code)
594 goto init_fail;
595 pixpaper_wait_for_panel(panel);
596
597 pixpaper_send_cmd(panel, PIXPAPER_CMD_PANEL_SETTING, &err);
598 pixpaper_send_data(panel, PIXPAPER_PSR_CONFIG, &err);
599 pixpaper_send_data(panel, PIXPAPER_PSR_CONFIG2, &err);
600 if (err.errno_code)
601 goto init_fail;
602 pixpaper_wait_for_panel(panel);
603
604 pixpaper_send_cmd(panel, PIXPAPER_CMD_POWER_SETTING, &err);
605 pixpaper_send_data(panel, PIXPAPER_PWR_CONFIG1, &err);
606 pixpaper_send_data(panel, PIXPAPER_PWR_CONFIG2, &err);
607 pixpaper_send_data(panel, PIXPAPER_PWR_VSP_8_2V, &err);
608 pixpaper_send_data(panel, PIXPAPER_PWR_VSPL_15V, &err);
609 pixpaper_send_data(panel, PIXPAPER_PWR_VSN_4V, &err);
610 pixpaper_send_data(panel, PIXPAPER_PWR_VSP_8_2V, &err);
611 if (err.errno_code)
612 goto init_fail;
613 pixpaper_wait_for_panel(panel);
614
615 pixpaper_send_cmd(panel, PIXPAPER_CMD_POWER_OFF_SEQUENCE, &err);
616 pixpaper_send_data(panel, PIXPAPER_PFS_CONFIG1, &err);
617 pixpaper_send_data(panel, PIXPAPER_PFS_CONFIG2, &err);
618 pixpaper_send_data(panel, PIXPAPER_PFS_CONFIG3, &err);
619 if (err.errno_code)
620 goto init_fail;
621 pixpaper_wait_for_panel(panel);
622
623 pixpaper_send_cmd(panel, PIXPAPER_CMD_BOOSTER_SOFT_START, &err);
624 pixpaper_send_data(panel, PIXPAPER_BTST_CONFIG1, &err);
625 pixpaper_send_data(panel, PIXPAPER_BTST_CONFIG2, &err);
626 pixpaper_send_data(panel, PIXPAPER_BTST_CONFIG3, &err);
627 pixpaper_send_data(panel, PIXPAPER_BTST_CONFIG4, &err);
628 pixpaper_send_data(panel, PIXPAPER_BTST_CONFIG5, &err);
629 pixpaper_send_data(panel, PIXPAPER_BTST_CONFIG6, &err);
630 pixpaper_send_data(panel, PIXPAPER_BTST_CONFIG7, &err);
631 if (err.errno_code)
632 goto init_fail;
633 pixpaper_wait_for_panel(panel);
634
635 pixpaper_send_cmd(panel, PIXPAPER_CMD_PLL_CONTROL, &err);
636 pixpaper_send_data(panel, PIXPAPER_PLL_CONFIG, &err);
637 if (err.errno_code)
638 goto init_fail;
639 pixpaper_wait_for_panel(panel);
640
641 pixpaper_send_cmd(panel, PIXPAPER_CMD_TEMP_SENSOR_CALIB, &err);
642 pixpaper_send_data(panel, PIXPAPER_TSE_CONFIG, &err);
643 if (err.errno_code)
644 goto init_fail;
645 pixpaper_wait_for_panel(panel);
646
647 pixpaper_send_cmd(panel, PIXPAPER_CMD_VCOM_INTERVAL, &err);
648 pixpaper_send_data(panel, PIXPAPER_CDI_CONFIG, &err);
649 if (err.errno_code)
650 goto init_fail;
651 pixpaper_wait_for_panel(panel);
652
653 pixpaper_send_cmd(panel, PIXPAPER_CMD_UNKNOWN_60, &err);
654 pixpaper_send_data(panel, PIXPAPER_UNKNOWN_60_CONFIG1, &err);
655 pixpaper_send_data(panel, PIXPAPER_UNKNOWN_60_CONFIG2, &err);
656 if (err.errno_code)
657 goto init_fail;
658 pixpaper_wait_for_panel(panel);
659
660 pixpaper_send_cmd(panel, PIXPAPER_CMD_RESOLUTION_SETTING, &err);
661 pixpaper_send_data(panel, PIXPAPER_TRES_HRES_H, &err);
662 pixpaper_send_data(panel, PIXPAPER_TRES_HRES_L, &err);
663 pixpaper_send_data(panel, PIXPAPER_TRES_VRES_H, &err);
664 pixpaper_send_data(panel, PIXPAPER_TRES_VRES_L, &err);
665 if (err.errno_code)
666 goto init_fail;
667 pixpaper_wait_for_panel(panel);
668
669 pixpaper_send_cmd(panel, PIXPAPER_CMD_GATE_SOURCE_START, &err);
670 pixpaper_send_data(panel, PIXPAPER_GSST_S_START, &err);
671 pixpaper_send_data(panel, PIXPAPER_GSST_RESERVED, &err);
672 pixpaper_send_data(panel, PIXPAPER_GSST_G_START_H, &err);
673 pixpaper_send_data(panel, PIXPAPER_GSST_G_START_L, &err);
674 if (err.errno_code)
675 goto init_fail;
676 pixpaper_wait_for_panel(panel);
677
678 pixpaper_send_cmd(panel, PIXPAPER_CMD_UNKNOWN_E7, &err);
679 pixpaper_send_data(panel, PIXPAPER_UNKNOWN_E7_CONFIG, &err);
680 if (err.errno_code)
681 goto init_fail;
682 pixpaper_wait_for_panel(panel);
683
684 pixpaper_send_cmd(panel, PIXPAPER_CMD_POWER_SAVING, &err);
685 pixpaper_send_data(panel, PIXPAPER_PWS_CONFIG, &err);
686 if (err.errno_code)
687 goto init_fail;
688 pixpaper_wait_for_panel(panel);
689
690 pixpaper_send_cmd(panel, PIXPAPER_CMD_UNKNOWN_E0, &err);
691 pixpaper_send_data(panel, PIXPAPER_UNKNOWN_E0_CONFIG, &err);
692 if (err.errno_code)
693 goto init_fail;
694 pixpaper_wait_for_panel(panel);
695
696 pixpaper_send_cmd(panel, PIXPAPER_CMD_UNKNOWN_B4, &err);
697 pixpaper_send_data(panel, PIXPAPER_UNKNOWN_B4_CONFIG, &err);
698 if (err.errno_code)
699 goto init_fail;
700 pixpaper_wait_for_panel(panel);
701
702 pixpaper_send_cmd(panel, PIXPAPER_CMD_UNKNOWN_B5, &err);
703 pixpaper_send_data(panel, PIXPAPER_UNKNOWN_B5_CONFIG, &err);
704 if (err.errno_code)
705 goto init_fail;
706 pixpaper_wait_for_panel(panel);
707
708 pixpaper_send_cmd(panel, PIXPAPER_CMD_UNKNOWN_E9, &err);
709 pixpaper_send_data(panel, PIXPAPER_UNKNOWN_E9_CONFIG, &err);
710 if (err.errno_code)
711 goto init_fail;
712 pixpaper_wait_for_panel(panel);
713
714 return 0;
715
716init_fail:
717 drm_err(&panel->drm, "Hardware initialization failed (err=%d)\n",
718 err.errno_code);
719 return err.errno_code;
720}
721
722/*
723 * Convert framebuffer pixels to 2-bit e-paper format:
724 * 00 - White
725 * 01 - Black
726 * 10 - Yellow
727 * 11 - Red
728 */
729static u8 pack_pixels_to_byte(__le32 *src_pixels, int i, int j,
730 struct drm_framebuffer *fb)
731{
732 u8 packed_byte = 0;
733 int k;
734
735 for (k = 0; k < 4; k++) {
736 int current_pixel_x = j * 4 + k;
737 u8 two_bit_val;
738
739 if (current_pixel_x < PIXPAPER_WIDTH) {
740 u32 pixel_offset =
741 (i * (fb->pitches[0] / 4)) + current_pixel_x;
742 u32 pixel = le32_to_cpu(src_pixels[pixel_offset]);
743 u32 r = (pixel >> 16) & 0xFF;
744 u32 g = (pixel >> 8) & 0xFF;
745 u32 b = pixel & 0xFF;
746
747 if (r < PIXPAPER_COLOR_THRESHOLD_LOW_CHANNEL &&
748 g < PIXPAPER_COLOR_THRESHOLD_LOW_CHANNEL &&
749 b < PIXPAPER_COLOR_THRESHOLD_LOW_CHANNEL) {
750 two_bit_val = 0b00;
751 } else if (r > PIXPAPER_COLOR_THRESHOLD_HIGH_CHANNEL &&
752 g > PIXPAPER_COLOR_THRESHOLD_HIGH_CHANNEL &&
753 b > PIXPAPER_COLOR_THRESHOLD_HIGH_CHANNEL) {
754 two_bit_val = 0b01;
755 } else if (r > PIXPAPER_COLOR_THRESHOLD_HIGH_CHANNEL &&
756 g < PIXPAPER_COLOR_THRESHOLD_LOW_CHANNEL &&
757 b < PIXPAPER_COLOR_THRESHOLD_LOW_CHANNEL) {
758 two_bit_val = 0b11;
759 } else if (r > PIXPAPER_COLOR_THRESHOLD_HIGH_CHANNEL &&
760 g > PIXPAPER_COLOR_THRESHOLD_YELLOW_MIN_GREEN &&
761 b < PIXPAPER_COLOR_THRESHOLD_LOW_CHANNEL) {
762 two_bit_val = 0b10;
763 } else {
764 two_bit_val = 0b01;
765 }
766 } else {
767 two_bit_val = 0b01;
768 }
769
770 packed_byte |= two_bit_val << ((3 - k) * 2);
771 }
772
773 return packed_byte;
774}
775
776static int pixpaper_plane_helper_atomic_check(struct drm_plane *plane,
777 struct drm_atomic_state *state)
778{
779 struct drm_plane_state *new_plane_state =
780 drm_atomic_get_new_plane_state(state, plane);
781 struct drm_crtc *new_crtc = new_plane_state->crtc;
782 struct drm_crtc_state *new_crtc_state = NULL;
783 int ret;
784
785 if (new_crtc)
786 new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc);
787
788 ret = drm_atomic_helper_check_plane_state(new_plane_state,
789 new_crtc_state, DRM_PLANE_NO_SCALING,
790 DRM_PLANE_NO_SCALING, false, false);
791 if (ret)
792 return ret;
793 else if (!new_plane_state->visible)
794 return 0;
795
796 return 0;
797}
798
799static int pixpaper_crtc_helper_atomic_check(struct drm_crtc *crtc,
800 struct drm_atomic_state *state)
801{
802 struct drm_crtc_state *crtc_state =
803 drm_atomic_get_new_crtc_state(state, crtc);
804
805 if (!crtc_state->enable)
806 return 0;
807
808 return drm_atomic_helper_check_crtc_primary_plane(crtc_state);
809}
810
811static void pixpaper_crtc_atomic_enable(struct drm_crtc *crtc,
812 struct drm_atomic_state *state)
813{
814 struct pixpaper_panel *panel = to_pixpaper_panel(crtc->dev);
815 struct drm_device *drm = &panel->drm;
816 int idx;
817 struct pixpaper_error_ctx err = { .errno_code = 0 };
818
819 if (!drm_dev_enter(drm, &idx))
820 return;
821
822 pixpaper_send_cmd(panel, PIXPAPER_CMD_POWER_ON, &err);
823 if (err.errno_code) {
824 drm_err_once(drm, "Failed to send PON command: %d\n", err.errno_code);
825 goto exit_drm_dev;
826 }
827
828 pixpaper_wait_for_panel(panel);
829
830 drm_dbg(drm, "Panel enabled and powered on\n");
831
832exit_drm_dev:
833 drm_dev_exit(idx);
834}
835
836static void pixpaper_crtc_atomic_disable(struct drm_crtc *crtc,
837 struct drm_atomic_state *state)
838{
839 struct pixpaper_panel *panel = to_pixpaper_panel(crtc->dev);
840 struct drm_device *drm = &panel->drm;
841 struct pixpaper_error_ctx err = { .errno_code = 0 };
842 int idx;
843
844 if (!drm_dev_enter(drm, &idx))
845 return;
846
847 pixpaper_send_cmd(panel, PIXPAPER_CMD_POWER_OFF, &err);
848 if (err.errno_code) {
849 drm_err_once(drm, "Failed to send POF command: %d\n", err.errno_code);
850 goto exit_drm_dev;
851 }
852 pixpaper_wait_for_panel(panel);
853
854 drm_dbg(drm, "Panel disabled\n");
855
856exit_drm_dev:
857 drm_dev_exit(idx);
858}
859
860static void pixpaper_plane_atomic_update(struct drm_plane *plane,
861 struct drm_atomic_state *state)
862{
863 struct drm_plane_state *plane_state =
864 drm_atomic_get_new_plane_state(state, plane);
865 struct drm_shadow_plane_state *shadow_plane_state =
866 to_drm_shadow_plane_state(plane_state);
867 struct drm_crtc *crtc = plane_state->crtc;
868 struct pixpaper_panel *panel = to_pixpaper_panel(crtc->dev);
869
870 struct drm_device *drm = &panel->drm;
871 struct drm_framebuffer *fb = plane_state->fb;
872 struct iosys_map map = shadow_plane_state->data[0];
873 void *vaddr = map.vaddr;
874 int i, j, idx;
875 __le32 *src_pixels = NULL;
876 struct pixpaper_error_ctx err = { .errno_code = 0 };
877
878 if (!drm_dev_enter(drm, &idx))
879 return;
880
881 drm_dbg(drm, "Starting frame update (phys=%dx%d, buf_w=%d)\n",
882 PIXPAPER_WIDTH, PIXPAPER_HEIGHT, PIXPAPER_PANEL_BUFFER_WIDTH);
883
884 if (!fb || !plane_state->visible) {
885 drm_err_once(drm, "No framebuffer or plane not visible, skipping update\n");
886 goto update_cleanup;
887 }
888
889 src_pixels = (__le32 *)vaddr;
890
891 pixpaper_send_cmd(panel, PIXPAPER_CMD_DATA_START_TRANSMISSION, &err);
892 if (err.errno_code)
893 goto update_cleanup;
894
895 pixpaper_wait_for_panel(panel);
896
897 for (i = 0; i < PIXPAPER_HEIGHT; i++) {
898 for (j = 0; j < PIXPAPER_PANEL_BUFFER_TWO_BYTES_PER_ROW; j++) {
899 u8 packed_byte =
900 pack_pixels_to_byte(src_pixels, i, j, fb);
901
902 pixpaper_wait_for_panel(panel);
903 pixpaper_send_data(panel, packed_byte, &err);
904 }
905 }
906 pixpaper_wait_for_panel(panel);
907
908 pixpaper_send_cmd(panel, PIXPAPER_CMD_POWER_ON, &err);
909 if (err.errno_code) {
910 drm_err_once(drm, "Failed to send PON command: %d\n", err.errno_code);
911 goto update_cleanup;
912 }
913 pixpaper_wait_for_panel(panel);
914
915 pixpaper_send_cmd(panel, PIXPAPER_CMD_DISPLAY_REFRESH, &err);
916 pixpaper_send_data(panel, PIXPAPER_DRF_VCOM_AC, &err);
917 if (err.errno_code) {
918 drm_err_once(drm, "Failed sending data after DRF: %d\n", err.errno_code);
919 goto update_cleanup;
920 }
921 pixpaper_wait_for_panel(panel);
922
923update_cleanup:
924 if (err.errno_code && err.errno_code != -ETIMEDOUT)
925 drm_err_once(drm, "Frame update function failed with error %d\n", err.errno_code);
926
927 drm_dev_exit(idx);
928}
929
930static const struct drm_display_mode pixpaper_mode = {
931 .clock = PIXPAPER_PIXEL_CLOCK,
932 .hdisplay = PIXPAPER_WIDTH,
933 .hsync_start = PIXPAPER_WIDTH + PIXPAPER_HFP,
934 .hsync_end = PIXPAPER_WIDTH + PIXPAPER_HFP + PIXPAPER_HSYNC,
935 .htotal = PIXPAPER_HTOTAL,
936 .vdisplay = PIXPAPER_HEIGHT,
937 .vsync_start = PIXPAPER_HEIGHT + PIXPAPER_VFP,
938 .vsync_end = PIXPAPER_HEIGHT + PIXPAPER_VFP + PIXPAPER_VSYNC,
939 .vtotal = PIXPAPER_VTOTAL,
940 .width_mm = PIXPAPER_WIDTH_MM,
941 .height_mm = PIXPAPER_HEIGHT_MM,
942 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
943};
944
945static int pixpaper_connector_get_modes(struct drm_connector *connector)
946{
947 return drm_connector_helper_get_modes_fixed(connector, &pixpaper_mode);
948}
949
950static const struct drm_plane_funcs pixpaper_plane_funcs = {
951 .update_plane = drm_atomic_helper_update_plane,
952 .disable_plane = drm_atomic_helper_disable_plane,
953 .destroy = drm_plane_cleanup,
954 DRM_GEM_SHADOW_PLANE_FUNCS,
955};
956
957static const struct drm_plane_helper_funcs pixpaper_plane_helper_funcs = {
958 DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
959 .atomic_check = pixpaper_plane_helper_atomic_check,
960 .atomic_update = pixpaper_plane_atomic_update,
961};
962
963static const struct drm_crtc_funcs pixpaper_crtc_funcs = {
964 .set_config = drm_atomic_helper_set_config,
965 .page_flip = drm_atomic_helper_page_flip,
966 .reset = drm_atomic_helper_crtc_reset,
967 .destroy = drm_crtc_cleanup,
968 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
969 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
970};
971
972static enum drm_mode_status
973pixpaper_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
974{
975 if (mode->hdisplay == PIXPAPER_WIDTH &&
976 mode->vdisplay == PIXPAPER_HEIGHT) {
977 return MODE_OK;
978 }
979 return MODE_BAD;
980}
981
982static const struct drm_crtc_helper_funcs pixpaper_crtc_helper_funcs = {
983 .mode_valid = pixpaper_mode_valid,
984 .atomic_check = pixpaper_crtc_helper_atomic_check,
985 .atomic_enable = pixpaper_crtc_atomic_enable,
986 .atomic_disable = pixpaper_crtc_atomic_disable,
987};
988
989static const struct drm_encoder_funcs pixpaper_encoder_funcs = {
990 .destroy = drm_encoder_cleanup,
991};
992
993static const struct drm_connector_funcs pixpaper_connector_funcs = {
994 .reset = drm_atomic_helper_connector_reset,
995 .fill_modes = drm_helper_probe_single_connector_modes,
996 .destroy = drm_connector_cleanup,
997 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
998 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
999};
1000
1001static const struct drm_connector_helper_funcs pixpaper_connector_helper_funcs = {
1002 .get_modes = pixpaper_connector_get_modes,
1003};
1004
1005DEFINE_DRM_GEM_FOPS(pixpaper_fops);
1006
1007static struct drm_driver pixpaper_drm_driver = {
1008 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
1009 .fops = &pixpaper_fops,
1010 .name = "pixpaper",
1011 .desc = "DRM driver for PIXPAPER e-ink",
1012 .major = 1,
1013 .minor = 0,
1014 DRM_GEM_SHMEM_DRIVER_OPS,
1015 DRM_FBDEV_SHMEM_DRIVER_OPS,
1016};
1017
1018static const struct drm_mode_config_funcs pixpaper_mode_config_funcs = {
1019 .fb_create = drm_gem_fb_create_with_dirty,
1020 .atomic_check = drm_atomic_helper_check,
1021 .atomic_commit = drm_atomic_helper_commit,
1022};
1023
1024static int pixpaper_probe(struct spi_device *spi)
1025{
1026 struct device *dev = &spi->dev;
1027 struct pixpaper_panel *panel;
1028 struct drm_device *drm;
1029 int ret;
1030
1031 panel = devm_drm_dev_alloc(dev, &pixpaper_drm_driver,
1032 struct pixpaper_panel, drm);
1033 if (IS_ERR(panel))
1034 return PTR_ERR(panel);
1035
1036 drm = &panel->drm;
1037 panel->spi = spi;
1038 spi_set_drvdata(spi, panel);
1039
1040 spi->mode = SPI_MODE_0;
1041 spi->bits_per_word = PIXPAPER_SPI_BITS_PER_WORD;
1042
1043 if (!spi->max_speed_hz) {
1044 drm_warn(drm,
1045 "spi-max-frequency not specified in DT, using default %u Hz\n",
1046 PIXPAPER_SPI_SPEED_DEFAULT);
1047 spi->max_speed_hz = PIXPAPER_SPI_SPEED_DEFAULT;
1048 }
1049
1050 ret = spi_setup(spi);
1051 if (ret < 0) {
1052 drm_err(drm, "SPI setup failed: %d\n", ret);
1053 return ret;
1054 }
1055
1056 if (!dev->dma_mask)
1057 dev->dma_mask = &dev->coherent_dma_mask;
1058 ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
1059 if (ret) {
1060 drm_err(drm, "Failed to set DMA mask: %d\n", ret);
1061 return ret;
1062 }
1063
1064 panel->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
1065 if (IS_ERR(panel->reset))
1066 return PTR_ERR(panel->reset);
1067
1068 panel->busy = devm_gpiod_get(dev, "busy", GPIOD_IN);
1069 if (IS_ERR(panel->busy))
1070 return PTR_ERR(panel->busy);
1071
1072 panel->dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_HIGH);
1073 if (IS_ERR(panel->dc))
1074 return PTR_ERR(panel->dc);
1075
1076 ret = pixpaper_panel_hw_init(panel);
1077 if (ret) {
1078 drm_err(drm, "Panel hardware initialization failed: %d\n", ret);
1079 return ret;
1080 }
1081
1082 ret = drmm_mode_config_init(drm);
1083 if (ret)
1084 return ret;
1085 drm->mode_config.funcs = &pixpaper_mode_config_funcs;
1086 drm->mode_config.min_width = PIXPAPER_WIDTH;
1087 drm->mode_config.max_width = PIXPAPER_WIDTH;
1088 drm->mode_config.min_height = PIXPAPER_HEIGHT;
1089 drm->mode_config.max_height = PIXPAPER_HEIGHT;
1090
1091 ret = drm_universal_plane_init(drm, &panel->plane, 1,
1092 &pixpaper_plane_funcs,
1093 (const uint32_t[]){ DRM_FORMAT_XRGB8888 },
1094 1, NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
1095 if (ret)
1096 return ret;
1097 drm_plane_helper_add(&panel->plane, &pixpaper_plane_helper_funcs);
1098
1099 ret = drm_crtc_init_with_planes(drm, &panel->crtc, &panel->plane, NULL,
1100 &pixpaper_crtc_funcs, NULL);
1101 if (ret)
1102 return ret;
1103 drm_crtc_helper_add(&panel->crtc, &pixpaper_crtc_helper_funcs);
1104
1105 ret = drm_encoder_init(drm, &panel->encoder, &pixpaper_encoder_funcs,
1106 DRM_MODE_ENCODER_NONE, NULL);
1107 if (ret)
1108 return ret;
1109 panel->encoder.possible_crtcs = drm_crtc_mask(&panel->crtc);
1110
1111 ret = drm_connector_init(drm, &panel->connector,
1112 &pixpaper_connector_funcs,
1113 DRM_MODE_CONNECTOR_SPI);
1114 if (ret)
1115 return ret;
1116
1117 drm_connector_helper_add(&panel->connector,
1118 &pixpaper_connector_helper_funcs);
1119 drm_connector_attach_encoder(&panel->connector, &panel->encoder);
1120
1121 drm_mode_config_reset(drm);
1122
1123 ret = drm_dev_register(drm, 0);
1124 if (ret)
1125 return ret;
1126
1127 drm_client_setup(drm, NULL);
1128
1129 return 0;
1130}
1131
1132static void pixpaper_remove(struct spi_device *spi)
1133{
1134 struct pixpaper_panel *panel = spi_get_drvdata(spi);
1135
1136 if (!panel)
1137 return;
1138
1139 drm_dev_unplug(&panel->drm);
1140 drm_atomic_helper_shutdown(&panel->drm);
1141}
1142
1143static const struct spi_device_id pixpaper_ids[] = { { "pixpaper", 0 }, {} };
1144MODULE_DEVICE_TABLE(spi, pixpaper_ids);
1145
1146static const struct of_device_id pixpaper_dt_ids[] = {
1147 { .compatible = "mayqueen,pixpaper" },
1148 {}
1149};
1150MODULE_DEVICE_TABLE(of, pixpaper_dt_ids);
1151
1152static struct spi_driver pixpaper_spi_driver = {
1153 .driver = {
1154 .name = "pixpaper",
1155 .of_match_table = pixpaper_dt_ids,
1156 },
1157 .id_table = pixpaper_ids,
1158 .probe = pixpaper_probe,
1159 .remove = pixpaper_remove,
1160};
1161
1162module_spi_driver(pixpaper_spi_driver);
1163
1164MODULE_AUTHOR("LiangCheng Wang");
1165MODULE_DESCRIPTION("DRM SPI driver for PIXPAPER e-ink panel");
1166MODULE_LICENSE("GPL");