mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
drm/ssd130x: Add support for the SSD133x OLED controller family
The Solomon SSD133x controllers (such as the SSD1331) are used by RGB dot matrix OLED panels, add a modesetting pipeline to support the chip family. The SSD133x controllers support 256 (8-bit) and 65k (16-bit) color depths but only the 256-color mode (DRM_FORMAT_RGB332) is implemented for now. Signed-off-by: Javier Martinez Canillas <javierm@redhat.com> Reviewed-by: Jocelyn Falempe <jfalempe@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20231229112026.2797483-5-javierm@redhat.com
This commit is contained in:
parent
e06b7373cf
commit
b4299c936d
|
|
@ -142,6 +142,11 @@ static const struct of_device_id ssd130x_of_match[] = {
|
||||||
.compatible = "solomon,ssd1327",
|
.compatible = "solomon,ssd1327",
|
||||||
.data = &ssd130x_variants[SSD1327_ID],
|
.data = &ssd130x_variants[SSD1327_ID],
|
||||||
},
|
},
|
||||||
|
/* ssd133x family */
|
||||||
|
{
|
||||||
|
.compatible = "solomon,ssd1331",
|
||||||
|
.data = &ssd130x_variants[SSD1331_ID],
|
||||||
|
},
|
||||||
{ /* sentinel */ }
|
{ /* sentinel */ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, ssd130x_of_match);
|
MODULE_DEVICE_TABLE(of, ssd130x_of_match);
|
||||||
|
|
@ -166,6 +171,8 @@ static const struct spi_device_id ssd130x_spi_table[] = {
|
||||||
{ "ssd1322", SSD1322_ID },
|
{ "ssd1322", SSD1322_ID },
|
||||||
{ "ssd1325", SSD1325_ID },
|
{ "ssd1325", SSD1325_ID },
|
||||||
{ "ssd1327", SSD1327_ID },
|
{ "ssd1327", SSD1327_ID },
|
||||||
|
/* ssd133x family */
|
||||||
|
{ "ssd1331", SSD1331_ID },
|
||||||
{ /* sentinel */ }
|
{ /* sentinel */ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(spi, ssd130x_spi_table);
|
MODULE_DEVICE_TABLE(spi, ssd130x_spi_table);
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,26 @@
|
||||||
#define SSD130X_SET_VCOMH_VOLTAGE 0xbe
|
#define SSD130X_SET_VCOMH_VOLTAGE 0xbe
|
||||||
#define SSD132X_SET_FUNCTION_SELECT_B 0xd5
|
#define SSD132X_SET_FUNCTION_SELECT_B 0xd5
|
||||||
|
|
||||||
|
/* ssd133x commands */
|
||||||
|
#define SSD133X_SET_COL_RANGE 0x15
|
||||||
|
#define SSD133X_SET_ROW_RANGE 0x75
|
||||||
|
#define SSD133X_CONTRAST_A 0x81
|
||||||
|
#define SSD133X_CONTRAST_B 0x82
|
||||||
|
#define SSD133X_CONTRAST_C 0x83
|
||||||
|
#define SSD133X_SET_MASTER_CURRENT 0x87
|
||||||
|
#define SSD132X_SET_PRECHARGE_A 0x8a
|
||||||
|
#define SSD132X_SET_PRECHARGE_B 0x8b
|
||||||
|
#define SSD132X_SET_PRECHARGE_C 0x8c
|
||||||
|
#define SSD133X_SET_DISPLAY_START 0xa1
|
||||||
|
#define SSD133X_SET_DISPLAY_OFFSET 0xa2
|
||||||
|
#define SSD133X_SET_DISPLAY_NORMAL 0xa4
|
||||||
|
#define SSD133X_SET_MASTER_CONFIG 0xad
|
||||||
|
#define SSD133X_POWER_SAVE_MODE 0xb0
|
||||||
|
#define SSD133X_PHASES_PERIOD 0xb1
|
||||||
|
#define SSD133X_SET_CLOCK_FREQ 0xb3
|
||||||
|
#define SSD133X_SET_PRECHARGE_VOLTAGE 0xbb
|
||||||
|
#define SSD133X_SET_VCOMH_VOLTAGE 0xbe
|
||||||
|
|
||||||
#define MAX_CONTRAST 255
|
#define MAX_CONTRAST 255
|
||||||
|
|
||||||
const struct ssd130x_deviceinfo ssd130x_variants[] = {
|
const struct ssd130x_deviceinfo ssd130x_variants[] = {
|
||||||
|
|
@ -180,6 +200,12 @@ const struct ssd130x_deviceinfo ssd130x_variants[] = {
|
||||||
.default_width = 128,
|
.default_width = 128,
|
||||||
.default_height = 128,
|
.default_height = 128,
|
||||||
.family_id = SSD132X_FAMILY,
|
.family_id = SSD132X_FAMILY,
|
||||||
|
},
|
||||||
|
/* ssd133x family */
|
||||||
|
[SSD1331_ID] = {
|
||||||
|
.default_width = 96,
|
||||||
|
.default_height = 64,
|
||||||
|
.family_id = SSD133X_FAMILY,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL_NS_GPL(ssd130x_variants, DRM_SSD130X);
|
EXPORT_SYMBOL_NS_GPL(ssd130x_variants, DRM_SSD130X);
|
||||||
|
|
@ -589,6 +615,117 @@ static int ssd132x_init(struct ssd130x_device *ssd130x)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ssd133x_init(struct ssd130x_device *ssd130x)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Set color A contrast */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_CONTRAST_A, 0x91);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set color B contrast */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_CONTRAST_B, 0x50);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set color C contrast */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_CONTRAST_C, 0x7d);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set master current */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_MASTER_CURRENT, 0x06);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set column start and end */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_COL_RANGE, 0x00, ssd130x->width - 1);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set row start and end */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_ROW_RANGE, 0x00, ssd130x->height - 1);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Horizontal Address Increment
|
||||||
|
* Normal order SA,SB,SC (e.g. RGB)
|
||||||
|
* COM Split Odd Even
|
||||||
|
* 256 color format
|
||||||
|
*/
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 2, SSD13XX_SET_SEG_REMAP, 0x20);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set display start and offset */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_DISPLAY_START, 0x00);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_DISPLAY_OFFSET, 0x00);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set display mode normal */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 1, SSD133X_SET_DISPLAY_NORMAL);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set multiplex ratio value */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 2, SSD13XX_SET_MULTIPLEX_RATIO, ssd130x->height - 1);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set master configuration */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_MASTER_CONFIG, 0x8e);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set power mode */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_POWER_SAVE_MODE, 0x0b);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set Phase 1 and 2 period */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_PHASES_PERIOD, 0x31);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set clock divider */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_CLOCK_FREQ, 0xf0);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set pre-charge A */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_PRECHARGE_A, 0x64);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set pre-charge B */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_PRECHARGE_B, 0x78);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set pre-charge C */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 2, SSD132X_SET_PRECHARGE_C, 0x64);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set pre-charge level */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_PRECHARGE_VOLTAGE, 0x3a);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set VCOMH voltage */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 2, SSD133X_SET_VCOMH_VOLTAGE, 0x3e);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int ssd130x_update_rect(struct ssd130x_device *ssd130x,
|
static int ssd130x_update_rect(struct ssd130x_device *ssd130x,
|
||||||
struct drm_rect *rect, u8 *buf,
|
struct drm_rect *rect, u8 *buf,
|
||||||
u8 *data_array)
|
u8 *data_array)
|
||||||
|
|
@ -753,6 +890,47 @@ static int ssd132x_update_rect(struct ssd130x_device *ssd130x,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ssd133x_update_rect(struct ssd130x_device *ssd130x,
|
||||||
|
struct drm_rect *rect, u8 *data_array,
|
||||||
|
unsigned int pitch)
|
||||||
|
{
|
||||||
|
unsigned int x = rect->x1;
|
||||||
|
unsigned int y = rect->y1;
|
||||||
|
unsigned int columns = drm_rect_width(rect);
|
||||||
|
unsigned int rows = drm_rect_height(rect);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The screen is divided in Segment and Common outputs, where
|
||||||
|
* COM0 to COM[N - 1] are the rows and SEG0 to SEG[M - 1] are
|
||||||
|
* the columns.
|
||||||
|
*
|
||||||
|
* Each Segment has a 8-bit pixel and each Common output has a
|
||||||
|
* row of pixels. When using the (default) horizontal address
|
||||||
|
* increment mode, each byte of data sent to the controller has
|
||||||
|
* a Segment (e.g: SEG0).
|
||||||
|
*
|
||||||
|
* When using the 256 color depth format, each pixel contains 3
|
||||||
|
* sub-pixels for color A, B and C. These have 3 bit, 3 bit and
|
||||||
|
* 2 bits respectively.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Set column start and end */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_COL_RANGE, x, columns - 1);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set row start and end */
|
||||||
|
ret = ssd130x_write_cmd(ssd130x, 3, SSD133X_SET_ROW_RANGE, y, rows - 1);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Write out update in one go since horizontal addressing mode is used */
|
||||||
|
ret = ssd130x_write_data(ssd130x, data_array, pitch * rows);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void ssd130x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array)
|
static void ssd130x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array)
|
||||||
{
|
{
|
||||||
unsigned int pages = DIV_ROUND_UP(ssd130x->height, SSD130X_PAGE_HEIGHT);
|
unsigned int pages = DIV_ROUND_UP(ssd130x->height, SSD130X_PAGE_HEIGHT);
|
||||||
|
|
@ -805,6 +983,22 @@ static void ssd132x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array)
|
||||||
ssd130x_write_data(ssd130x, data_array, columns * height);
|
ssd130x_write_data(ssd130x, data_array, columns * height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ssd133x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array)
|
||||||
|
{
|
||||||
|
const struct drm_format_info *fi = drm_format_info(DRM_FORMAT_RGB332);
|
||||||
|
unsigned int pitch;
|
||||||
|
|
||||||
|
if (!fi)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pitch = drm_format_info_min_pitch(fi, 0, ssd130x->width);
|
||||||
|
|
||||||
|
memset(data_array, 0, pitch * ssd130x->height);
|
||||||
|
|
||||||
|
/* Write out update in one go since horizontal addressing mode is used */
|
||||||
|
ssd130x_write_data(ssd130x, data_array, pitch * ssd130x->height);
|
||||||
|
}
|
||||||
|
|
||||||
static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb,
|
static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb,
|
||||||
const struct iosys_map *vmap,
|
const struct iosys_map *vmap,
|
||||||
struct drm_rect *rect,
|
struct drm_rect *rect,
|
||||||
|
|
@ -866,6 +1060,36 @@ static int ssd132x_fb_blit_rect(struct drm_framebuffer *fb,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ssd133x_fb_blit_rect(struct drm_framebuffer *fb,
|
||||||
|
const struct iosys_map *vmap,
|
||||||
|
struct drm_rect *rect, u8 *data_array,
|
||||||
|
struct drm_format_conv_state *fmtcnv_state)
|
||||||
|
{
|
||||||
|
struct ssd130x_device *ssd130x = drm_to_ssd130x(fb->dev);
|
||||||
|
const struct drm_format_info *fi = drm_format_info(DRM_FORMAT_RGB332);
|
||||||
|
unsigned int dst_pitch;
|
||||||
|
struct iosys_map dst;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!fi)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
dst_pitch = drm_format_info_min_pitch(fi, 0, drm_rect_width(rect));
|
||||||
|
|
||||||
|
ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
iosys_map_set_vaddr(&dst, data_array);
|
||||||
|
drm_fb_xrgb8888_to_rgb332(&dst, &dst_pitch, vmap, fb, rect, fmtcnv_state);
|
||||||
|
|
||||||
|
drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
|
||||||
|
|
||||||
|
ssd133x_update_rect(ssd130x, rect, data_array, dst_pitch);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int ssd130x_primary_plane_atomic_check(struct drm_plane *plane,
|
static int ssd130x_primary_plane_atomic_check(struct drm_plane *plane,
|
||||||
struct drm_atomic_state *state)
|
struct drm_atomic_state *state)
|
||||||
{
|
{
|
||||||
|
|
@ -964,6 +1188,29 @@ static int ssd132x_primary_plane_atomic_check(struct drm_plane *plane,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ssd133x_primary_plane_atomic_check(struct drm_plane *plane,
|
||||||
|
struct drm_atomic_state *state)
|
||||||
|
{
|
||||||
|
struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
|
||||||
|
struct drm_crtc *crtc = plane_state->crtc;
|
||||||
|
struct drm_crtc_state *crtc_state = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (crtc)
|
||||||
|
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||||
|
|
||||||
|
ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
|
||||||
|
DRM_PLANE_NO_SCALING,
|
||||||
|
DRM_PLANE_NO_SCALING,
|
||||||
|
false, false);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
else if (!plane_state->visible)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void ssd130x_primary_plane_atomic_update(struct drm_plane *plane,
|
static void ssd130x_primary_plane_atomic_update(struct drm_plane *plane,
|
||||||
struct drm_atomic_state *state)
|
struct drm_atomic_state *state)
|
||||||
{
|
{
|
||||||
|
|
@ -1034,6 +1281,39 @@ static void ssd132x_primary_plane_atomic_update(struct drm_plane *plane,
|
||||||
drm_dev_exit(idx);
|
drm_dev_exit(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ssd133x_primary_plane_atomic_update(struct drm_plane *plane,
|
||||||
|
struct drm_atomic_state *state)
|
||||||
|
{
|
||||||
|
struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
|
||||||
|
struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
|
||||||
|
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
|
||||||
|
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);
|
||||||
|
struct ssd130x_crtc_state *ssd130x_crtc_state = to_ssd130x_crtc_state(crtc_state);
|
||||||
|
struct drm_framebuffer *fb = plane_state->fb;
|
||||||
|
struct drm_atomic_helper_damage_iter iter;
|
||||||
|
struct drm_device *drm = plane->dev;
|
||||||
|
struct drm_rect dst_clip;
|
||||||
|
struct drm_rect damage;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
if (!drm_dev_enter(drm, &idx))
|
||||||
|
return;
|
||||||
|
|
||||||
|
drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
|
||||||
|
drm_atomic_for_each_plane_damage(&iter, &damage) {
|
||||||
|
dst_clip = plane_state->dst;
|
||||||
|
|
||||||
|
if (!drm_rect_intersect(&dst_clip, &damage))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ssd133x_fb_blit_rect(fb, &shadow_plane_state->data[0], &dst_clip,
|
||||||
|
ssd130x_crtc_state->data_array,
|
||||||
|
&shadow_plane_state->fmtcnv_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_dev_exit(idx);
|
||||||
|
}
|
||||||
|
|
||||||
static void ssd130x_primary_plane_atomic_disable(struct drm_plane *plane,
|
static void ssd130x_primary_plane_atomic_disable(struct drm_plane *plane,
|
||||||
struct drm_atomic_state *state)
|
struct drm_atomic_state *state)
|
||||||
{
|
{
|
||||||
|
|
@ -1082,6 +1362,30 @@ static void ssd132x_primary_plane_atomic_disable(struct drm_plane *plane,
|
||||||
drm_dev_exit(idx);
|
drm_dev_exit(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ssd133x_primary_plane_atomic_disable(struct drm_plane *plane,
|
||||||
|
struct drm_atomic_state *state)
|
||||||
|
{
|
||||||
|
struct drm_device *drm = plane->dev;
|
||||||
|
struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);
|
||||||
|
struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
|
||||||
|
struct drm_crtc_state *crtc_state;
|
||||||
|
struct ssd130x_crtc_state *ssd130x_crtc_state;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
if (!plane_state->crtc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
crtc_state = drm_atomic_get_new_crtc_state(state, plane_state->crtc);
|
||||||
|
ssd130x_crtc_state = to_ssd130x_crtc_state(crtc_state);
|
||||||
|
|
||||||
|
if (!drm_dev_enter(drm, &idx))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ssd133x_clear_screen(ssd130x, ssd130x_crtc_state->data_array);
|
||||||
|
|
||||||
|
drm_dev_exit(idx);
|
||||||
|
}
|
||||||
|
|
||||||
/* Called during init to allocate the plane's atomic state. */
|
/* Called during init to allocate the plane's atomic state. */
|
||||||
static void ssd130x_primary_plane_reset(struct drm_plane *plane)
|
static void ssd130x_primary_plane_reset(struct drm_plane *plane)
|
||||||
{
|
{
|
||||||
|
|
@ -1144,6 +1448,12 @@ static const struct drm_plane_helper_funcs ssd130x_primary_plane_helper_funcs[]
|
||||||
.atomic_check = ssd132x_primary_plane_atomic_check,
|
.atomic_check = ssd132x_primary_plane_atomic_check,
|
||||||
.atomic_update = ssd132x_primary_plane_atomic_update,
|
.atomic_update = ssd132x_primary_plane_atomic_update,
|
||||||
.atomic_disable = ssd132x_primary_plane_atomic_disable,
|
.atomic_disable = ssd132x_primary_plane_atomic_disable,
|
||||||
|
},
|
||||||
|
[SSD133X_FAMILY] = {
|
||||||
|
DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
|
||||||
|
.atomic_check = ssd133x_primary_plane_atomic_check,
|
||||||
|
.atomic_update = ssd133x_primary_plane_atomic_update,
|
||||||
|
.atomic_disable = ssd133x_primary_plane_atomic_disable,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1214,6 +1524,33 @@ static int ssd132x_crtc_atomic_check(struct drm_crtc *crtc,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ssd133x_crtc_atomic_check(struct drm_crtc *crtc,
|
||||||
|
struct drm_atomic_state *state)
|
||||||
|
{
|
||||||
|
struct drm_device *drm = crtc->dev;
|
||||||
|
struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);
|
||||||
|
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||||
|
struct ssd130x_crtc_state *ssd130x_state = to_ssd130x_crtc_state(crtc_state);
|
||||||
|
const struct drm_format_info *fi = drm_format_info(DRM_FORMAT_RGB332);
|
||||||
|
unsigned int pitch;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!fi)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ret = drm_crtc_helper_atomic_check(crtc, state);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
pitch = drm_format_info_min_pitch(fi, 0, ssd130x->width);
|
||||||
|
|
||||||
|
ssd130x_state->data_array = kmalloc(pitch * ssd130x->height, GFP_KERNEL);
|
||||||
|
if (!ssd130x_state->data_array)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Called during init to allocate the CRTC's atomic state. */
|
/* Called during init to allocate the CRTC's atomic state. */
|
||||||
static void ssd130x_crtc_reset(struct drm_crtc *crtc)
|
static void ssd130x_crtc_reset(struct drm_crtc *crtc)
|
||||||
{
|
{
|
||||||
|
|
@ -1275,6 +1612,10 @@ static const struct drm_crtc_helper_funcs ssd130x_crtc_helper_funcs[] = {
|
||||||
.mode_valid = ssd130x_crtc_mode_valid,
|
.mode_valid = ssd130x_crtc_mode_valid,
|
||||||
.atomic_check = ssd132x_crtc_atomic_check,
|
.atomic_check = ssd132x_crtc_atomic_check,
|
||||||
},
|
},
|
||||||
|
[SSD133X_FAMILY] = {
|
||||||
|
.mode_valid = ssd130x_crtc_mode_valid,
|
||||||
|
.atomic_check = ssd133x_crtc_atomic_check,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct drm_crtc_funcs ssd130x_crtc_funcs = {
|
static const struct drm_crtc_funcs ssd130x_crtc_funcs = {
|
||||||
|
|
@ -1337,6 +1678,31 @@ static void ssd132x_encoder_atomic_enable(struct drm_encoder *encoder,
|
||||||
ssd130x_power_off(ssd130x);
|
ssd130x_power_off(ssd130x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ssd133x_encoder_atomic_enable(struct drm_encoder *encoder,
|
||||||
|
struct drm_atomic_state *state)
|
||||||
|
{
|
||||||
|
struct drm_device *drm = encoder->dev;
|
||||||
|
struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = ssd130x_power_on(ssd130x);
|
||||||
|
if (ret)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ret = ssd133x_init(ssd130x);
|
||||||
|
if (ret)
|
||||||
|
goto power_off;
|
||||||
|
|
||||||
|
ssd130x_write_cmd(ssd130x, 1, SSD13XX_DISPLAY_ON);
|
||||||
|
|
||||||
|
backlight_enable(ssd130x->bl_dev);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
power_off:
|
||||||
|
ssd130x_power_off(ssd130x);
|
||||||
|
}
|
||||||
|
|
||||||
static void ssd130x_encoder_atomic_disable(struct drm_encoder *encoder,
|
static void ssd130x_encoder_atomic_disable(struct drm_encoder *encoder,
|
||||||
struct drm_atomic_state *state)
|
struct drm_atomic_state *state)
|
||||||
{
|
{
|
||||||
|
|
@ -1358,6 +1724,10 @@ static const struct drm_encoder_helper_funcs ssd130x_encoder_helper_funcs[] = {
|
||||||
[SSD132X_FAMILY] = {
|
[SSD132X_FAMILY] = {
|
||||||
.atomic_enable = ssd132x_encoder_atomic_enable,
|
.atomic_enable = ssd132x_encoder_atomic_enable,
|
||||||
.atomic_disable = ssd130x_encoder_atomic_disable,
|
.atomic_disable = ssd130x_encoder_atomic_disable,
|
||||||
|
},
|
||||||
|
[SSD133X_FAMILY] = {
|
||||||
|
.atomic_enable = ssd133x_encoder_atomic_enable,
|
||||||
|
.atomic_disable = ssd130x_encoder_atomic_disable,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,8 @@
|
||||||
|
|
||||||
enum ssd130x_family_ids {
|
enum ssd130x_family_ids {
|
||||||
SSD130X_FAMILY,
|
SSD130X_FAMILY,
|
||||||
SSD132X_FAMILY
|
SSD132X_FAMILY,
|
||||||
|
SSD133X_FAMILY
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ssd130x_variants {
|
enum ssd130x_variants {
|
||||||
|
|
@ -39,6 +40,8 @@ enum ssd130x_variants {
|
||||||
SSD1322_ID,
|
SSD1322_ID,
|
||||||
SSD1325_ID,
|
SSD1325_ID,
|
||||||
SSD1327_ID,
|
SSD1327_ID,
|
||||||
|
/* ssd133x family */
|
||||||
|
SSD1331_ID,
|
||||||
NR_SSD130X_VARIANTS
|
NR_SSD130X_VARIANTS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user