From e7154e9565200fbede1a8f0cd5cb2d872c19fef0 Mon Sep 17 00:00:00 2001 From: Zheng Yang Date: Thu, 31 Jul 2014 18:05:01 +0800 Subject: [PATCH] rk3036 tve: register fb notifier. --- .../video/rockchip/tve/rk3036/rk3036_tve.c | 238 +++++++++++------- .../video/rockchip/tve/rk3036/rk3036_tve.h | 60 +++-- 2 files changed, 177 insertions(+), 121 deletions(-) diff --git a/drivers/video/rockchip/tve/rk3036/rk3036_tve.c b/drivers/video/rockchip/tve/rk3036/rk3036_tve.c index 537674fa8e9c..11095bfc1275 100644 --- a/drivers/video/rockchip/tve/rk3036/rk3036_tve.c +++ b/drivers/video/rockchip/tve/rk3036/rk3036_tve.c @@ -1,8 +1,8 @@ /* - * rk3036_tve.c + * rk3036_tve.c * * Driver for rockchip rk3036 tv encoder control - * Copyright (C) 2014 + * Copyright (C) 2014 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -21,7 +21,6 @@ #include #include "rk3036_tve.h" -//#define DEBUG #ifdef DEBUG #define TVEDBG(format, ...) \ printk(KERN_INFO "RK3036 TVE: " format "\n", ## __VA_ARGS__) @@ -29,13 +28,13 @@ #define TVEDBG(format, ...) #endif -static const struct fb_videomode rk3036_cvbs_mode [] = { - /*name refresh xres yres pixclock h_bp h_fp v_bp v_fp h_pw v_pw polariry PorI flag*/ - {"NTSC",60, 720, 480, 27000000, 57, 19, 19, 0, 62, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED, 0}, - {"PAL", 50, 720, 576, 27000000, 69, 12, 19, 2, 63, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED, 0}, +static const struct fb_videomode rk3036_cvbs_mode[] = { + /*name refresh xres yres pixclock h_bp h_fp v_bp v_fp h_pw v_pw polariry PorI flag*/ + {"NTSC", 60, 720, 480, 27000000, 57, 19, 19, 0, 62, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED, 0}, + {"PAL", 50, 720, 576, 27000000, 69, 12, 19, 2, 63, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED, 0}, }; -static struct rk3036_tve *rk3036_tve = NULL; +static struct rk3036_tve *rk3036_tve; #define tve_writel(offset, v) writel_relaxed(v, rk3036_tve->regbase + offset) #define tve_readl(offset) readl_relaxed(rk3036_tve->regbase + offset) @@ -43,10 +42,10 @@ static struct rk3036_tve *rk3036_tve = NULL; static void dac_enable(bool enable) { u32 mask, val; - - TVEDBG("%s enable %d\n", __FUNCTION__, enable); - - if(enable) { + + TVEDBG("%s enable %d\n", __func__, enable); + + if (enable) { mask = m_VBG_EN | m_DAC_EN; val = mask; } else { @@ -56,98 +55,101 @@ static void dac_enable(bool enable) grf_writel(RK3036_GRF_SOC_CON3, (mask << 16) | val); } -static void tve_set_mode (int mode) +static void tve_set_mode(int mode) { - TVEDBG("%s mode %d\n", __FUNCTION__, mode); - + TVEDBG("%s mode %d\n", __func__, mode); + tve_writel(TV_RESET, v_RESET(1)); udelay(100); tve_writel(TV_RESET, v_RESET(0)); - - tve_writel(TV_CTRL, v_CVBS_MODE(mode) | v_CLK_UPSTREAM_EN(2) | - v_TIMING_EN(2) | v_LUMA_FILTER_GAIN(0) | - v_LUMA_FILTER_UPSAMPLE(0) | v_CSC_PATH(0) ); + + tve_writel(TV_CTRL, v_CVBS_MODE(mode) | v_CLK_UPSTREAM_EN(2) | + v_TIMING_EN(2) | v_LUMA_FILTER_GAIN(0) | + v_LUMA_FILTER_UPSAMPLE(1) | v_CSC_PATH(0)); tve_writel(TV_LUMA_FILTER0, 0x02ff0000); tve_writel(TV_LUMA_FILTER1, 0xF40202fd); tve_writel(TV_LUMA_FILTER2, 0xF332d919); - - if(mode == TVOUT_CVBS_NTSC) { - tve_writel(TV_ROUTING, v_DAC_SENSE_EN(0) | v_Y_IRE_7_5(1) | - v_Y_AGC_PULSE_ON(1) | v_Y_VIDEO_ON(1) | - v_Y_SYNC_ON(1) | v_PIC_MODE(mode)); - tve_writel(TV_BW_CTRL, v_CHROMA_BW(BP_FILTER_NTSC) | v_COLOR_DIFF_BW(COLOR_DIFF_FILTER_BW_1_3)); - tve_writel(TV_SATURATION, 0x0052543C); + + if (mode == TVOUT_CVBS_NTSC) { + tve_writel(TV_ROUTING, v_DAC_SENSE_EN(0) | v_Y_IRE_7_5(1) | + v_Y_AGC_PULSE_ON(0) | v_Y_VIDEO_ON(1) | + v_YPP_MODE(1) | v_Y_SYNC_ON(1) | v_PIC_MODE(mode)); + tve_writel(TV_BW_CTRL, v_CHROMA_BW(BP_FILTER_NTSC) | + v_COLOR_DIFF_BW(COLOR_DIFF_FILTER_BW_1_3)); + tve_writel(TV_SATURATION, 0x0042543C); tve_writel(TV_BRIGHTNESS_CONTRAST, 0x00008300); - + tve_writel(TV_FREQ_SC, 0x21F07BD7); tve_writel(TV_SYNC_TIMING, 0x00C07a81); - tve_writel(TV_ADJ_TIMING, 0x96B40000); + tve_writel(TV_ADJ_TIMING, 0x96B40000 | 0x70); tve_writel(TV_ACT_ST, 0x001500D6); - tve_writel(TV_ACT_TIMING, 0x169800FC); + tve_writel(TV_ACT_TIMING, 0x069800FC | (1 << 12) | (1 << 28)); } else if (mode == TVOUT_CVBS_PAL) { - tve_writel(TV_ROUTING, v_DAC_SENSE_EN(0) | v_Y_IRE_7_5(0) | - v_Y_AGC_PULSE_ON(1) | v_Y_VIDEO_ON(1) | - v_Y_SYNC_ON(1) | v_CVBS_MODE(mode)); - tve_writel(TV_BW_CTRL, v_CHROMA_BW(BP_FILTER_PAL) | v_COLOR_DIFF_BW(COLOR_DIFF_FILTER_BW_1_3)); - tve_writel(TV_SATURATION, 0x002e553c); - tve_writel(TV_BRIGHTNESS_CONTRAST, 0x00007579); - + tve_writel(TV_ROUTING, v_DAC_SENSE_EN(0) | v_Y_IRE_7_5(0) | + v_Y_AGC_PULSE_ON(0) | v_Y_VIDEO_ON(1) | + v_YPP_MODE(1) | v_Y_SYNC_ON(1) | v_PIC_MODE(mode)); + tve_writel(TV_BW_CTRL, v_CHROMA_BW(BP_FILTER_PAL) | + v_COLOR_DIFF_BW(COLOR_DIFF_FILTER_BW_1_3)); + tve_writel(TV_SATURATION, 0x00325c40); + tve_writel(TV_BRIGHTNESS_CONTRAST, 0x00008b00); + tve_writel(TV_FREQ_SC, 0x2A098ACB); tve_writel(TV_SYNC_TIMING, 0x00C28381); - tve_writel(TV_ADJ_TIMING, 0xB6C00880); + tve_writel(TV_ADJ_TIMING, (0xc << 28) | 0x06c00800 | 0x80); tve_writel(TV_ACT_ST, 0x001500F6); - tve_writel(TV_ACT_TIMING, 0x2694011D); + tve_writel(TV_ACT_TIMING, 0x0694011D | (1 << 12) | (2 << 28)); + tve_writel(TV_ADJ_TIMING, (0xa << 28) | 0x06c00800 | 0x80); } } static int tve_switch_fb(const struct fb_videomode *modedb, int enable) -{ +{ struct rk_screen *screen; - - if(modedb == NULL) + + if (modedb == NULL) return -1; - screen = kzalloc(sizeof(struct rk_screen), GFP_KERNEL); - if(screen == NULL) + screen = kzalloc(sizeof(screen), GFP_KERNEL); + if (screen == NULL) return -1; - - memset(screen, 0, sizeof(struct rk_screen)); + + memset(screen, 0, sizeof(struct rk_screen)); /* screen type & face */ screen->type = SCREEN_TVOUT; screen->face = OUT_P888; - + screen->mode = *modedb; - + /* Pin polarity */ - if(FB_SYNC_HOR_HIGH_ACT & modedb->sync) + if (FB_SYNC_HOR_HIGH_ACT & modedb->sync) screen->pin_hsync = 1; else screen->pin_hsync = 0; - if(FB_SYNC_VERT_HIGH_ACT & modedb->sync) + if (FB_SYNC_VERT_HIGH_ACT & modedb->sync) screen->pin_vsync = 1; else screen->pin_vsync = 0; - + screen->pin_den = 0; screen->pin_dclk = 0; screen->pixelrepeat = 1; - + /* Swap rule */ screen->swap_rb = 0; screen->swap_rg = 0; screen->swap_gb = 0; screen->swap_delta = 0; screen->swap_dumy = 0; - + /* Operation function*/ screen->init = NULL; - screen->standby = NULL; - + screen->standby = NULL; + rk_fb_switch_screen(screen, enable, 0); kfree(screen); - if(enable) { - if(screen->mode.yres == 480) + if (enable) { + if (screen->mode.yres == 480) tve_set_mode(TVOUT_CVBS_NTSC); else tve_set_mode(TVOUT_CVBS_PAL); @@ -157,18 +159,16 @@ static int tve_switch_fb(const struct fb_videomode *modedb, int enable) static int cvbs_set_enable(struct rk_display_device *device, int enable) { - TVEDBG("%s enable %d\n", __FUNCTION__, enable); - if(rk3036_tve->enable != enable) - { + TVEDBG("%s enable %d\n", __func__, enable); + if (rk3036_tve->enable != enable) { rk3036_tve->enable = enable; - if(rk3036_tve->suspend) + if (rk3036_tve->suspend) return 0; - - if(enable == 0) { + + if (enable == 0) { dac_enable(false); tve_switch_fb(rk3036_tve->mode, 0); - } - else if(enable == 1) { + } else if (enable == 1) { tve_switch_fb(rk3036_tve->mode, 1); dac_enable(true); } @@ -178,51 +178,97 @@ static int cvbs_set_enable(struct rk_display_device *device, int enable) static int cvbs_get_enable(struct rk_display_device *device) { - TVEDBG("%s enable %d\n", __FUNCTION__, rk3036_tve->enable); + TVEDBG("%s enable %d\n", __func__, rk3036_tve->enable); return rk3036_tve->enable; } static int cvbs_get_status(struct rk_display_device *device) { - TVEDBG("%s \n", __FUNCTION__); return 1; } -static int cvbs_get_modelist(struct rk_display_device *device, struct list_head **modelist) +static int +cvbs_get_modelist(struct rk_display_device *device, struct list_head **modelist) { - TVEDBG("%s \n", __FUNCTION__); *modelist = &(rk3036_tve->modelist); return 0; } -static int cvbs_set_mode(struct rk_display_device *device, struct fb_videomode *mode) +static int +cvbs_set_mode(struct rk_display_device *device, struct fb_videomode *mode) { int i; - TVEDBG("%s \n", __FUNCTION__); - for(i = 0; i < ARRAY_SIZE(rk3036_cvbs_mode); i++) - { - if(fb_mode_is_equal(&rk3036_cvbs_mode[i], mode)) - { - if( rk3036_tve->mode != &rk3036_cvbs_mode[i] ) { - rk3036_tve->mode = (struct fb_videomode *)&rk3036_cvbs_mode[i]; - if(rk3036_tve->enable && !rk3036_tve->suspend) + + for (i = 0; i < ARRAY_SIZE(rk3036_cvbs_mode); i++) { + if (fb_mode_is_equal(&rk3036_cvbs_mode[i], mode)) { + if (rk3036_tve->mode != &rk3036_cvbs_mode[i]) { + rk3036_tve->mode = + (struct fb_videomode *)&rk3036_cvbs_mode[i]; + if (rk3036_tve->enable && !rk3036_tve->suspend) dac_enable(false); tve_switch_fb(rk3036_tve->mode, 1); + msleep(500); dac_enable(true); } return 0; } } - + TVEDBG("%s\n", __func__); return -1; } -static int cvbs_get_mode(struct rk_display_device *device, struct fb_videomode *mode) +static int +cvbs_get_mode(struct rk_display_device *device, struct fb_videomode *mode) { *mode = *(rk3036_tve->mode); return 0; } +static int +tve_fb_event_notify(struct notifier_block *self, + unsigned long action, void *data) +{ + struct fb_event *event = data; + int blank_mode = *((int *)event->data); + + if (action == FB_EARLY_EVENT_BLANK) { + switch (blank_mode) { + case FB_BLANK_UNBLANK: + break; + default: + TVEDBG("suspend hdmi\n"); + if (!rk3036_tve->suspend) { + rk3036_tve->suspend = 1; + if (rk3036_tve->enable) { + tve_switch_fb(rk3036_tve->mode, 0); + dac_enable(false); + } + } + break; + } + } else if (action == FB_EVENT_BLANK) { + switch (blank_mode) { + case FB_BLANK_UNBLANK: + TVEDBG("resume hdmi\n"); + if (rk3036_tve->suspend) { + rk3036_tve->suspend = 0; + if (rk3036_tve->enable) { + tve_switch_fb(rk3036_tve->mode, 1); + dac_enable(true); + } + } + break; + default: + break; + } + } + return NOTIFY_OK; +} + +static struct notifier_block tve_fb_notifier = { + .notifier_call = tve_fb_event_notify, +}; + static struct rk_display_ops cvbs_display_ops = { .setenable = cvbs_set_enable, .getenable = cvbs_get_enable, @@ -232,7 +278,8 @@ static struct rk_display_ops cvbs_display_ops = { .getmode = cvbs_get_mode, }; -static int display_cvbs_probe(struct rk_display_device *device, void *devdata) +static int +display_cvbs_probe(struct rk_display_device *device, void *devdata) { device->owner = THIS_MODULE; strcpy(device->type, "TV"); @@ -251,10 +298,10 @@ static int rk3036_tve_probe(struct platform_device *pdev) { struct resource *res; int i; - - rk3036_tve = devm_kzalloc(&pdev->dev, sizeof(struct rk3036_tve), - GFP_KERNEL); - if(!rk3036_tve) { + + rk3036_tve = devm_kzalloc(&pdev->dev, + sizeof(struct rk3036_tve), GFP_KERNEL); + if (!rk3036_tve) { dev_err(&pdev->dev, "rk3036 tv encoder device kmalloc fail!"); return -ENOMEM; } @@ -263,31 +310,34 @@ static int rk3036_tve_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); rk3036_tve->reg_phy_base = res->start; rk3036_tve->len = resource_size(res); - rk3036_tve->regbase = devm_ioremap_resource(&pdev->dev, res); + rk3036_tve->regbase = ioremap(res->start, rk3036_tve->len); if (IS_ERR(rk3036_tve->regbase)) { - dev_err(&pdev->dev, "rk3036 tv encoder device map registers failed!"); + dev_err(&pdev->dev, + "rk3036 tv encoder device map registers failed!"); return PTR_ERR(rk3036_tve->regbase); - } - + } + INIT_LIST_HEAD(&(rk3036_tve->modelist)); - for(i = 0; i < ARRAY_SIZE(rk3036_cvbs_mode); i++) + for (i = 0; i < ARRAY_SIZE(rk3036_cvbs_mode); i++) fb_add_videomode(&rk3036_cvbs_mode[i], &(rk3036_tve->modelist)); - rk3036_tve->mode = (struct fb_videomode*)&rk3036_cvbs_mode[1]; - rk3036_tve->ddev = rk_display_device_register(&display_cvbs, &pdev->dev, NULL); + rk3036_tve->mode = (struct fb_videomode *)&rk3036_cvbs_mode[1]; + rk3036_tve->ddev = + rk_display_device_register(&display_cvbs, &pdev->dev, NULL); rk_display_device_enable(rk3036_tve->ddev); - + + fb_register_client(&tve_fb_notifier); dev_info(&pdev->dev, "rk3036 tv encoder probe ok\n"); return 0; } static void rk3036_tve_shutdown(struct platform_device *pdev) { - } #if defined(CONFIG_OF) static const struct of_device_id rk3036_tve_dt_ids[] = { {.compatible = "rockchip,rk3036-tve",}, + {.compatible = "rockchip,rk312x-tve",}, {} }; #endif @@ -310,7 +360,7 @@ static int __init rk3036_tve_init(void) static void __exit rk3036_tve_exit(void) { - platform_driver_unregister(&rk3036_tve_driver); + platform_driver_unregister(&rk3036_tve_driver); } module_init(rk3036_tve_init); diff --git a/drivers/video/rockchip/tve/rk3036/rk3036_tve.h b/drivers/video/rockchip/tve/rk3036/rk3036_tve.h index d36573e0f5b0..25ebd2190520 100644 --- a/drivers/video/rockchip/tve/rk3036/rk3036_tve.h +++ b/drivers/video/rockchip/tve/rk3036/rk3036_tve.h @@ -8,14 +8,14 @@ #define m_LUMA_FILTER_GAIN (3 << 9) #define m_LUMA_FILTER_BW (1 << 8) #define m_CSC_PATH (3 << 1) - - #define v_CVBS_MODE(x) ( (x & 1) << 24) - #define v_CLK_UPSTREAM_EN(x) ( (x & 3) << 18) - #define v_TIMING_EN(x) ( (x & 3) << 16) - #define v_LUMA_FILTER_GAIN(x) ( (x & 3) << 9) - #define v_LUMA_FILTER_UPSAMPLE(x) ( (x & 1) << 8) - #define v_CSC_PATH(x) ( (x & 3) << 1) - + + #define v_CVBS_MODE(x) ((x & 1) << 24) + #define v_CLK_UPSTREAM_EN(x) ((x & 3) << 18) + #define v_TIMING_EN(x) ((x & 3) << 16) + #define v_LUMA_FILTER_GAIN(x) ((x & 3) << 9) + #define v_LUMA_FILTER_UPSAMPLE(x) ((x & 1) << 8) + #define v_CSC_PATH(x) ((x & 3) << 1) + #define TV_SYNC_TIMING (0x04) #define TV_ACT_TIMING (0x08) #define TV_ADJ_TIMING (0x0c) @@ -30,27 +30,29 @@ #define m_Y_AGC_PULSE_ON (1 << 15) #define m_Y_VIDEO_ON (1 << 11) #define m_Y_SYNC_ON (1 << 7) + #define m_YPP_MODE (1 << 3) #define m_MONO_EN (1 << 2) #define m_PIC_MODE (1 << 1) - - #define v_DAC_SENSE_EN(x) ( (x & 1) << 27) - #define v_Y_IRE_7_5(x) ( (x & 1) << 19) - #define v_Y_AGC_PULSE_ON(x) ( (x & 1) << 15) - #define v_Y_VIDEO_ON(x) ( (x & 1) << 11) - #define v_Y_SYNC_ON(x) ( (x & 1) << 7) - #define v_MONO_EN(x) ( (x & 1) << 2) - #define v_PIC_MODE(x) ( (x & 1) << 1) - + + #define v_DAC_SENSE_EN(x) ((x & 1) << 27) + #define v_Y_IRE_7_5(x) ((x & 1) << 19) + #define v_Y_AGC_PULSE_ON(x) ((x & 1) << 15) + #define v_Y_VIDEO_ON(x) ((x & 1) << 11) + #define v_Y_SYNC_ON(x) ((x & 1) << 7) + #define v_YPP_MODE(x) ((x & 1) << 3) + #define v_MONO_EN(x) ((x & 1) << 2) + #define v_PIC_MODE(x) ((x & 1) << 1) + #define TV_SYNC_ADJUST (0x50) #define TV_STATUS (0x54) #define TV_RESET (0x68) - #define m_RESET (1 << 1); - #define v_RESET(x) ( (x & 1) << 1) + #define m_RESET (1 << 1) + #define v_RESET(x) ((x & 1) << 1) #define TV_SATURATION (0x78) #define TV_BW_CTRL (0x8C) #define m_CHROMA_BW (3 << 4) #define m_COLOR_DIFF_BW (0xf) - + enum { BP_FILTER_PASS = 0, BP_FILTER_NTSC, @@ -62,10 +64,10 @@ COLOR_DIFF_FILTER_BW_1_3, COLOR_DIFF_FILTER_BW_2_0 }; - + #define v_CHROMA_BW(x) ((3 & x) << 4) #define v_COLOR_DIFF_BW(x) (0xF & x) - + #define TV_BRIGHTNESS_CONTRAST (0x90) #define m_EXTREF_EN (1 << 0) @@ -74,6 +76,7 @@ #define m_SENSE_EN (1 << 3) #define m_BIAS_EN (7 << 4) #define m_DAC_GAIN (0x3f << 7) +#define v_DAC_GAIN(x) ((x & 0x3f) << 7) enum { TVOUT_CVBS_NTSC = 0, @@ -82,14 +85,17 @@ enum { #define TVOUT_DEAULT TVOUT_CVBS_PAL -#define grf_writel(offset, v) do{ writel_relaxed(v, RK_GRF_VIRT + offset);dsb();} while (0) +#define grf_writel(offset, v) do { \ + writel_relaxed(v, RK_GRF_VIRT + offset); \ + dsb(); \ + } while (0) struct rk3036_tve { - struct device *dev; + struct device *dev; void __iomem *regbase; - u32 reg_phy_base; /* physical basic address of register*/ - u32 len; /* physical map length of register*/ - + u32 reg_phy_base; + u32 len; + struct rk_display_device *ddev; unsigned int enable; unsigned int suspend; -- 2.34.1