From: hwangjae lee Date: Thu, 2 Aug 2018 01:06:14 +0000 (+0900) Subject: [9609] fbdev: panel: added sysfs for supporting CABC of NT36672A Panel X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=17e08221323f6deeb16f050ae0ff59acb44d09d8;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git [9609] fbdev: panel: added sysfs for supporting CABC of NT36672A Panel Change-Id: I3b30b191121ab0db21280f528b7226d1e22fbf90 Signed-off-by: hwangjae lee --- diff --git a/drivers/video/fbdev/exynos/dpu20/dsim_drv.c b/drivers/video/fbdev/exynos/dpu20/dsim_drv.c index de9da141f0fe..9c409c6ebbb3 100644 --- a/drivers/video/fbdev/exynos/dpu20/dsim_drv.c +++ b/drivers/video/fbdev/exynos/dpu20/dsim_drv.c @@ -1940,7 +1940,6 @@ static int dsim_probe(struct platform_device *pdev) #if defined(READ_ESD_SOLUTION_TEST) dsim_create_esd_test_sysfs(dsim); #endif -#endif #ifdef DPHY_LOOP dsim_reg_set_dphy_loop_back_test(dsim->id); diff --git a/drivers/video/fbdev/exynos/dpu20/panels/Kconfig b/drivers/video/fbdev/exynos/dpu20/panels/Kconfig index f987588b7111..5892ef14db00 100644 --- a/drivers/video/fbdev/exynos/dpu20/panels/Kconfig +++ b/drivers/video/fbdev/exynos/dpu20/panels/Kconfig @@ -41,7 +41,7 @@ config EXYNOS_DECON_LCD_S6E3FA7 config EXYNOS_DECON_LCD_NT36672A depends on EXYNOS_DECON_LCD && EXYNOS_MIPI_DSIM - tristate "NT3667A TFT FHD+ LCD driver(1080 x 2246)" + tristate "NT36672A TFT FHD+ LCD driver(1080 x 2246)" default n config EXYNOS_DECON_LCD_EMUL_DISP diff --git a/drivers/video/fbdev/exynos/dpu20/panels/nt36672a_mipi_lcd.c b/drivers/video/fbdev/exynos/dpu20/panels/nt36672a_mipi_lcd.c index 5550f0c02b8e..f09b013722bc 100644 --- a/drivers/video/fbdev/exynos/dpu20/panels/nt36672a_mipi_lcd.c +++ b/drivers/video/fbdev/exynos/dpu20/panels/nt36672a_mipi_lcd.c @@ -29,6 +29,18 @@ static struct dsim_device *dsim_base; static struct backlight_device *bd; +#if defined(CONFIG_EXYNOS_PANEL_CABC) +struct panel_device { + struct device *dev; + struct dsim_device *dsim; + struct mutex lock; + int cabc_mode; +}; + +struct panel_device *panel_drvdata; +struct class *panel_class; +#endif + static int nt36672a_get_brightness(struct backlight_device *bd) { return bd->props.brightness; @@ -165,27 +177,191 @@ static const struct backlight_ops nt36672a_backlight_ops = { .update_status = nt36672a_set_brightness, }; +#if defined(CONFIG_EXYNOS_PANEL_CABC) +static int nt36672a_cabc_mode(struct dsim_device *dsim, int mode) +{ + int ret = 0; + int count; + unsigned char buf[] = {0x0, 0x0}; + unsigned char SEQ_CABC_CMD[] = {0x55, 0x00, 0x00}; + unsigned char cmd = MIPI_DCS_WRITE_POWER_SAVE; /* 0x55 */ + + dsim_dbg("%s: CABC mode[%d] write/read\n", __func__, mode); + + switch (mode) { + /* read */ + case CABC_READ_MODE: + cmd = MIPI_DCS_GET_POWER_SAVE; /* 0x56 */ + ret = dsim_read_data(dsim, MIPI_DSI_DCS_READ, cmd, 0x1, buf); + if (ret < 0) { + pr_err("CABC REG(0x%02X) read failure!\n", cmd); + count = 0; + } else { + pr_info("CABC REG(0x%02X) read success: 0x%02x\n", + cmd, *(unsigned int *)buf & 0xFF); + count = 1; + } + return count; + + /* write */ + case POWER_SAVE_OFF: + SEQ_CABC_CMD[1] = CABC_OFF; + break; + case POWER_SAVE_LOW: + SEQ_CABC_CMD[1] = CABC_USER_IMAGE; + break; + case POWER_SAVE_MEDIUM: + SEQ_CABC_CMD[1] = CABC_STILL_PICTURE; + break; + case POWER_SAVE_HIGH: + SEQ_CABC_CMD[1] = CABC_MOVING_IMAGE; + break; + default: + pr_err("Unavailable CABC mode(%d)!\n", mode); + return -EINVAL; + } + + ret = dsim_write_data(dsim, MIPI_DSI_DCS_LONG_WRITE, + (unsigned long)SEQ_CABC_CMD /*cmd*/, + ARRAY_SIZE(SEQ_CABC_CMD)); + if (ret < 0) { + pr_err("CABC write command failure!\n"); + count = 0; + } else { + dsim_dbg("CABC write command success!\n"); + count = ARRAY_SIZE(SEQ_CABC_CMD); + } + + return count; +} + +static ssize_t panel_cabc_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t count = 0; + int ret = 0; + struct panel_device *panel = dev_get_drvdata(dev); + + mutex_lock(&panel->lock); + + ret = nt36672a_cabc_mode(panel->dsim, CABC_READ_MODE); + + mutex_unlock(&panel->lock); + + count = snprintf(buf, PAGE_SIZE, "cabc_mode = %d, ret = %d\n", + panel->cabc_mode, ret); + + return count; +} + +static ssize_t panel_cabc_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + unsigned int value = 0; + struct panel_device *panel = dev_get_drvdata(dev); + + ret = kstrtouint(buf, 0, &value); + if (ret < 0) + return ret; + + mutex_lock(&panel->lock); + panel->cabc_mode = value; + mutex_unlock(&panel->lock); + + pr_info("%s: %d\n", __func__, value); + + nt36672a_cabc_mode(panel->dsim, panel->cabc_mode); + + return count; +} + +static DEVICE_ATTR(cabc_mode, 0660, panel_cabc_mode_show, + panel_cabc_mode_store); + +static struct attribute *panel_attrs[] = { + &dev_attr_cabc_mode.attr, + NULL, +}; +ATTRIBUTE_GROUPS(panel); +#endif + static int nt36672a_probe(struct dsim_device *dsim) { + int ret = 1; + struct panel_device *panel; + static unsigned int panel_no; + dsim_base = dsim; bd = backlight_device_register("backlight_0", NULL, - NULL, &nt36672a_backlight_ops, NULL); + NULL, &nt36672a_backlight_ops, NULL); if (IS_ERR(bd)) pr_err("failed to register backlight device!\n"); bd->props.max_brightness = MAX_BRIGHTNESS; bd->props.brightness = DEFAULT_BRIGHTNESS; +#if defined(CONFIG_EXYNOS_PANEL_CABC) + panel = kzalloc(sizeof(struct panel_device), GFP_KERNEL); + if (!panel) { + pr_err("failed to allocate panel\n"); + ret = -ENOMEM; + goto exit0; + } - return 0; + panel_drvdata = panel; + + panel->dsim = dsim; + panel->cabc_mode = 0; + + if (IS_ERR_OR_NULL(panel_class)) { + panel_class = class_create(THIS_MODULE, "panel"); + if (IS_ERR_OR_NULL(panel_class)) { + pr_err("failed to create panel class\n"); + ret = -EINVAL; + goto exit1; + } + + panel_class->dev_groups = panel_groups; + } + + panel->dev = device_create(panel_class, dsim->dev, 0, + &panel, !panel_no ? "panel" : "panel%d", panel_no); + if (IS_ERR_OR_NULL(panel->dev)) { + pr_err("failed to create panel device\n"); + ret = -EINVAL; + goto exit2; + } + + mutex_init(&panel->lock); + dev_set_drvdata(panel->dev, panel); + + panel_no++; + + return ret; + +exit2: + class_destroy(panel_class); +exit1: + kfree(panel); +exit0: +#endif + return ret; } static int nt36672a_displayon(struct dsim_device *dsim) { +#if defined(CONFIG_EXYNOS_PANEL_CABC) + struct panel_device *panel = panel_drvdata; +#endif dsim_info("%s +\n", __func__); nt36672a_lcd_init(dsim->id, &dsim->lcd_info); nt36672a_lcd_enable(dsim->id); dsim_info("%s -\n", __func__); +#if defined(CONFIG_EXYNOS_PANEL_CABC) + if (panel) + nt36672a_cabc_mode(dsim, panel->cabc_mode); +#endif return 1; } diff --git a/drivers/video/fbdev/exynos/dpu20/panels/nt36672a_param.h b/drivers/video/fbdev/exynos/dpu20/panels/nt36672a_param.h index 5973b30450e2..ec6ff3579b46 100644 --- a/drivers/video/fbdev/exynos/dpu20/panels/nt36672a_param.h +++ b/drivers/video/fbdev/exynos/dpu20/panels/nt36672a_param.h @@ -12,6 +12,32 @@ #ifndef __NT36672A_PARAM_H__ #define __NT36672A_PARAM_H__ +#if defined(CONFIG_EXYNOS_PANEL_CABC) +/* + *cabc_mode[1:0] must be re-mapped according to DDI command + *3FA0 is OLED, so CABC command is not supported. + *Following values represent for ACL2 control of 3FA0. + *- [2'b00] ACL off + *- [2'b01] ACL low + *- [2'b10] ACL mid + *- [2'b11] ACL high + */ +enum cabc_mode { + CABC_OFF = 0, + CABC_USER_IMAGE, + CABC_STILL_PICTURE, + CABC_MOVING_IMAGE, + CABC_READ_MODE = 0x80, +}; + +enum power_mode { + POWER_SAVE_OFF = 0, + POWER_SAVE_LOW = 1, + POWER_SAVE_MEDIUM = 2, + POWER_SAVE_HIGH = 3, + POWER_SAVE_MAX = 4, +}; +#endif /* MIPI commands list */ static const unsigned char SEQ_SLEEP_OUT[] = { 0x11,