EXYNOS_DISPLAY_TYPE_VIDI,
};
+enum exynos_drm_display_mode {
+ EXYNOS_DISPLAY_OUTPUT_NONE,
+ EXYNOS_DISPLAY_OUTPUT_WB,
+};
+
+/*
+ * A structure of wb setting infomation.
+ *
+ * @enable: enable flag for wb.
+ * @refresh: HZ of the refresh rate.
+ */
+struct drm_exynos_display_set_wb {
+ __u32 enable;
+ __u32 refresh;
+};
+
/*
* Exynos drm common overlay structure.
*
*/
void exynos_platform_device_ipp_unregister(void);
+extern int exynos_drm_ippnb_register(struct notifier_block *nb);
+extern int exynos_drm_ippnb_unregister(struct notifier_block *nb);
+
#ifdef CONFIG_DRM_EXYNOS_DPI
int exynos_dpi_probe(struct device *dev);
int exynos_dpi_remove(struct device *dev);
struct drm_exynos_ipp_property *property;
struct drm_exynos_ipp_config *config;
struct drm_exynos_pos img_pos[EXYNOS_DRM_OPS_MAX];
- struct drm_exynos_ipp_set_wb set_wb;
+ struct drm_exynos_display_set_wb set_wb;
int ret, i;
u32 cfg0, cfg1;
set_wb.enable = 1;
set_wb.refresh = property->refresh_rate;
- exynos_drm_ippnb_send_event(IPP_SET_WRITEBACK, (void *)&set_wb);
+ exynos_drm_ippnb_send_event(EXYNOS_DISPLAY_OUTPUT_WB, (void *)&set_wb);
break;
case IPP_CMD_OUTPUT:
default:
static void fimc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd)
{
struct fimc_context *ctx = get_fimc_context(dev);
- struct drm_exynos_ipp_set_wb set_wb = {0, 0};
+ struct drm_exynos_display_set_wb set_wb = {0, 0};
u32 cfg;
DRM_DEBUG_KMS("%s:cmd[%d]\n", __func__, cmd);
fimc_write(ctx, cfg, EXYNOS_MSCTRL);
break;
case IPP_CMD_WB:
- exynos_drm_ippnb_send_event(IPP_SET_WRITEBACK, (void *)&set_wb);
+ exynos_drm_ippnb_send_event(EXYNOS_DISPLAY_OUTPUT_WB, (void *)&set_wb);
break;
case IPP_CMD_OUTPUT:
default:
struct exynos_drm_panel_info panel;
struct fimd_driver_data *driver_data;
+ struct notifier_block nb_ctrl;
};
static const struct of_device_id fimd_driver_dt_match[] = {
return IRQ_HANDLED;
}
+static void fimd_set_writeback(struct fimd_context *ctx, int enable,
+ unsigned int refresh)
+{
+ u32 vidcon0 = readl(ctx->regs + VIDCON0);
+ u32 vidcon2 = readl(ctx->regs + VIDCON2);
+
+ DRM_DEBUG_KMS("%s:wb[%d]refresh[%d]\n",
+ __func__, enable, refresh);
+
+ vidcon0 &= ~VIDCON0_VIDOUT_MASK;
+ vidcon2 &= ~(VIDCON2_WB_MASK |
+ VIDCON2_WB_SKIP_MASK |
+ VIDCON2_TVFMTSEL_SW |
+ VIDCON2_TVFORMATSEL_MASK);
+
+ if (enable) {
+ vidcon0 |= VIDCON0_VIDOUT_WB_RGB;
+ vidcon2 |= (VIDCON2_WB_ENABLE |
+ VIDCON2_TVFMTSEL_SW |
+ VIDCON2_TVFMTSEL1_YUV444);
+
+ if (refresh >= 60 || refresh == 0)
+ DRM_INFO("%s:refresh[%d],forced set to 60hz.\n",
+ __func__, refresh);
+ else if (refresh >= 30)
+ vidcon2 |= VIDCON2_WB_SKIP_1_2;
+ else if (refresh >= 20)
+ vidcon2 |= VIDCON2_WB_SKIP_1_3;
+ else if (refresh >= 15)
+ vidcon2 |= VIDCON2_WB_SKIP_1_4;
+ else
+ vidcon2 |= VIDCON2_WB_SKIP_1_5;
+ } else {
+ if (ctx->i80_if)
+ vidcon0 |= VIDCON0_VIDOUT_I80_LDI0;
+ else
+ vidcon0 |= VIDCON0_VIDOUT_RGB;
+ vidcon2 |= VIDCON2_WB_DISABLE;
+ }
+
+ writel(vidcon0, ctx->regs + VIDCON0);
+ writel(vidcon2, ctx->regs + VIDCON2);
+}
+
+static int fimd_notifier_ctrl(struct notifier_block *this,
+ unsigned long event, void *_data)
+{
+ struct fimd_context *ctx = container_of(this,
+ struct fimd_context, nb_ctrl);
+
+ if (ctx->suspended)
+ return -EPERM;
+
+ switch (event) {
+ case EXYNOS_DISPLAY_OUTPUT_WB: {
+ struct drm_exynos_display_set_wb *set_wb =
+ (struct drm_exynos_display_set_wb *)_data;
+ unsigned int refresh = set_wb->refresh;
+ int enable = *((int *)&set_wb->enable);
+
+ fimd_set_writeback(ctx, enable, refresh);
+ }
+ break;
+ default:
+ /* ToDo : for checking use case */
+ DRM_INFO("%s:event[0x%x]\n", __func__, (unsigned int)event);
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
static int fimd_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
init_waitqueue_head(&ctx->wait_vsync_queue);
atomic_set(&ctx->wait_vsync_event, 0);
+ ctx->nb_ctrl.notifier_call = fimd_notifier_ctrl;
+ ret = exynos_drm_ippnb_register(&ctx->nb_ctrl);
+ if (ret) {
+ dev_err(dev, "could not register fimd notify callback\n");
+ return ret;
+ }
+
platform_set_drvdata(pdev, &fimd_manager);
fimd_manager.ctx = ctx;
static int fimd_remove(struct platform_device *pdev)
{
struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
+ struct fimd_context *ctx = mgr->ctx;
+ int ret;
exynos_dpi_remove(&pdev->dev);
+ ret = exynos_drm_ippnb_unregister(&ctx->nb_ctrl);
+ if (ret) {
+ dev_err(&pdev->dev, "could not unregister fimd notify callback\n");
+ return ret;
+ }
+
exynos_drm_manager_unregister(&fimd_manager);
fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
#define for_each_ipp_planar(pos) \
for (pos = 0; pos < EXYNOS_DRM_PLANAR_MAX; pos++)
-#define IPP_GET_LCD_WIDTH _IOR('F', 302, int)
-#define IPP_GET_LCD_HEIGHT _IOR('F', 303, int)
-#define IPP_SET_WRITEBACK _IOW('F', 304, u32)
-
/* definition of state */
enum drm_exynos_ipp_state {
IPP_STATE_IDLE,
};
/*
- * A structure of wb setting infomation.
- *
- * @enable: enable flag for wb.
- * @refresh: HZ of the refresh rate.
- */
-struct drm_exynos_ipp_set_wb {
- __u32 enable;
- __u32 refresh;
-};
-
-/*
* A structure of event work information.
*
* @work: work structure.
struct drm_file *file);
extern int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data,
struct drm_file *file);
-extern int exynos_drm_ippnb_register(struct notifier_block *nb);
-extern int exynos_drm_ippnb_unregister(struct notifier_block *nb);
extern int exynos_drm_ippnb_send_event(unsigned long val, void *v);
extern void ipp_sched_cmd(struct work_struct *work);
extern void ipp_sched_event(struct work_struct *work);
#define VIDCON2 0x08
#define VIDCON2_EN601 (1 << 23)
+#define VIDCON2_WB_ENABLE (1 << 15)
+#define VIDCON2_WB_MASK (1 << 15)
+#define VIDCON2_WB_DISABLE (0 << 15)
#define VIDCON2_TVFMTSEL_SW (1 << 14)
+#define VIDCON2_TVFMTSEL_SW_MASK (1 << 14)
+#define VIDCON2_TVFORMATSEL_MASK (0x3 << 12)
#define VIDCON2_TVFMTSEL1_MASK (0x3 << 12)
#define VIDCON2_TVFMTSEL1_SHIFT 12
#define VIDCON2_ORGYCbCr (1 << 8)
#define VIDCON2_YUVORDCrCb (1 << 7)
+#define VIDCON2_WB_SKIP_1_2 (0x1 << 0)
+#define VIDCON2_WB_SKIP_1_3 (0x2 << 0)
+#define VIDCON2_WB_SKIP_1_4 (0x3 << 0)
+#define VIDCON2_WB_SKIP_1_5 (0x4 << 0)
+#define VIDCON2_WB_SKIP_MASK (0x1f << 0)
+
/* PRTCON (S3C6410, S5PC100)
* Might not be present in the S3C6410 documentation,
* but tests prove it's there almost for sure; shouldn't hurt in any case.