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