From: xuhuicong Date: Wed, 24 Jul 2013 01:28:11 +0000 (+0800) Subject: rk3028a hdmi: add 3028a hdmi driver as compatible with rk616 hdmi X-Git-Tag: firefly_0821_release~6855^2~2 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=67e0e6fce85c43addb7220fcb6a909a9e2bf1295;p=firefly-linux-kernel-4.4.55.git rk3028a hdmi: add 3028a hdmi driver as compatible with rk616 hdmi --- diff --git a/arch/arm/mach-rk2928/devices.c b/arch/arm/mach-rk2928/devices.c index ba673a7ac64f..e4cc759ecd00 100644 --- a/arch/arm/mach-rk2928/devices.c +++ b/arch/arm/mach-rk2928/devices.c @@ -567,7 +567,7 @@ static struct platform_device device_nand = { .num_resources = ARRAY_SIZE(resources_nand), }; #endif -#ifdef CONFIG_HDMI_RK2928 +#if defined(CONFIG_HDMI_RK2928) || defined(CONFIG_HDMI_RK616) static struct resource resource_hdmi[] = { [0] = { .start = RK2928_HDMI_PHYS, @@ -582,12 +582,17 @@ static struct resource resource_hdmi[] = { }; static struct platform_device device_hdmi = { +#ifdef CONFIG_HDMI_RK616 + .name = "rk616-hdmi", +#else .name = "rk2928-hdmi", +#endif .id = -1, .num_resources = ARRAY_SIZE(resource_hdmi), .resource = resource_hdmi, }; #endif + #ifdef CONFIG_RGA_RK30 static struct resource resource_rga[] = { [0] = { @@ -797,7 +802,7 @@ static int __init rk2928_init_devices(void) rk_serial_debug_init(DEBUG_UART_BASE, IRQ_DEBUG_UART, IRQ_UART_SIGNAL, -1); #endif rk2928_init_i2s(); -#ifdef CONFIG_HDMI_RK2928 +#if defined(CONFIG_HDMI_RK2928) || defined(CONFIG_HDMI_RK616) platform_device_register(&device_hdmi); #endif platform_device_register(&device_arm_pmu); diff --git a/drivers/video/rockchip/hdmi/chips/Kconfig b/drivers/video/rockchip/hdmi/chips/Kconfig index 69064120c159..b8797ffdeab8 100755 --- a/drivers/video/rockchip/hdmi/chips/Kconfig +++ b/drivers/video/rockchip/hdmi/chips/Kconfig @@ -39,7 +39,8 @@ endif config HDMI_RK616 bool "RK616 HDMI support" - depends on MFD_RK616 + depends on MFD_RK616 || ARCH_RK3026 + default y help Support rk616 hdmi if you say y here diff --git a/drivers/video/rockchip/hdmi/chips/rk616/Kconfig b/drivers/video/rockchip/hdmi/chips/rk616/Kconfig index dff44615ab97..68cedb7eed0c 100755 --- a/drivers/video/rockchip/hdmi/chips/rk616/Kconfig +++ b/drivers/video/rockchip/hdmi/chips/rk616/Kconfig @@ -1,6 +1,6 @@ config HDCP_RK616 bool "RK616 HDCP support" - depends on HDMI_RK616 + depends on HDMI_RK616 || ARCH_RK3026 default n help HDCP Interface. This adds the High Definition Content Protection Interface. diff --git a/drivers/video/rockchip/hdmi/chips/rk616/rk616_hdmi.c b/drivers/video/rockchip/hdmi/chips/rk616/rk616_hdmi.c index a51139a1eb00..df3ca6876b9b 100755 --- a/drivers/video/rockchip/hdmi/chips/rk616/rk616_hdmi.c +++ b/drivers/video/rockchip/hdmi/chips/rk616/rk616_hdmi.c @@ -38,29 +38,19 @@ static int rk616_hdmi_reg_show(struct seq_file *s, void *v) { int i = 0; u32 val = 0; - struct mfd_rk616 *rk616 = s->private; - if(!rk616) - { - dev_err(rk616->dev,"no mfd rk616!\n"); - return 0; - } - seq_printf(s, "\n>>>rk616_ctl reg"); for (i = 0; i < 16; i++) { seq_printf(s, " %2x", i); } seq_printf(s, "\n-----------------------------------------------------------------"); - for(i=0;i<= (PHY_PRE_DIV_RATIO << 2);i+=4) - { - rk616->read_dev(rk616,RK616_HDMI_BASE + i,&val); - //seq_printf(s,"reg%02x>>0x%08x\n",(i>>2),val); - if((i>>2)%16==0) - seq_printf(s,"\n>>>rk616_ctl %2x:",i>>2); + for(i=0; i<= PHY_PRE_DIV_RATIO; i++) { + hdmi_readl(i, &val); + if(i%16==0) + seq_printf(s,"\n>>>rk616_ctl %2x:", i); seq_printf(s," %02x",val); } - seq_printf(s, "\n-----------------------------------------------------------------\n"); return 0; @@ -68,24 +58,19 @@ static int rk616_hdmi_reg_show(struct seq_file *s, void *v) static ssize_t rk616_hdmi_reg_write (struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct mfd_rk616 *rk616 = file->f_path.dentry->d_inode->i_private; u32 reg; u32 val; char kbuf[25]; if (copy_from_user(kbuf, buf, count)) return -EFAULT; sscanf(kbuf, "%x%x", ®, &val); - if ((reg < 0) || (reg > 0xed)) - { - printk("it is no hdmi reg\n"); + if ((reg < 0) || (reg > 0xed)) { + dev_info(hdmi->dev, "it is no hdmi reg\n"); return count; } - printk("/**********rk616 reg config******/"); - printk("\n reg=%x val=%x\n", reg, val); - - //sscanf(kbuf, "%x%x", ®, &val); - dev_dbg(rk616->dev,"%s:reg:0x%04x val:0x%08x\n",__func__,reg, val); - rk616->write_dev(rk616, RK616_HDMI_BASE + (reg << 2), &val); + dev_info(hdmi->dev, "/**********rk616 reg config******/"); + dev_info(hdmi->dev, "\n reg=%x val=%x\n", reg, val); + hdmi_writel(reg, val); return count; } @@ -166,10 +151,8 @@ static void hdmi_early_resume(struct early_suspend *h) // hdmi_irq(); rk616_hdmi_work(); } - - if (rk616_hdmi->rk616_drv->pdata->hdmi_irq == INVALID_GPIO) + if (rk616_hdmi->rk616_drv && rk616_hdmi->rk616_drv->pdata->hdmi_irq == INVALID_GPIO) queue_delayed_work(hdmi->workqueue, &rk616_hdmi->rk616_delay_work, 100); - queue_delayed_work(hdmi->workqueue, &hdmi->delay_work, msecs_to_jiffies(10)); mutex_unlock(&hdmi->enable_mutex); return; @@ -187,13 +170,13 @@ static void rk616_delay_work_func(struct work_struct *work) rk616_hdmi_work(); } - if (rk616_hdmi->rk616_drv->pdata->hdmi_irq == INVALID_GPIO) { + if (rk616_hdmi->rk616_drv && rk616_hdmi->rk616_drv->pdata->hdmi_irq == INVALID_GPIO) { queue_delayed_work(hdmi->workqueue, &rk616_hdmi->rk616_delay_work, 100); } } } -static void rk616_irq_work_func(struct work_struct *work) +static void __maybe_unused rk616_irq_work_func(struct work_struct *work) { if((hdmi->suspend == 0) && (hdmi->enable == 1)) { rk616_hdmi_work(); @@ -202,29 +185,32 @@ static void rk616_irq_work_func(struct work_struct *work) enable_irq(hdmi->irq); } -#if 1 static irqreturn_t rk616_hdmi_irq(int irq, void *dev_id) { struct work_struct *rk616_irq_work_struct; + struct rk616_hdmi *rk616_hdmi; - rk616_irq_work_struct = dev_id; - disable_irq_nosync(hdmi->irq); - //printk(KERN_INFO "rk616_hdmi_irq irq triggered.\n"); - queue_work(hdmi->workqueue, rk616_irq_work_struct); + rk616_hdmi = container_of(hdmi, struct rk616_hdmi, g_hdmi); + if(rk616_hdmi->rk616_drv) { + rk616_irq_work_struct = dev_id; + disable_irq_nosync(hdmi->irq); + queue_work(hdmi->workqueue, rk616_irq_work_struct); + } else { + /* 3028a hdmi */ + if((hdmi->suspend == 0) && (hdmi->enable == 1)) { + printk(KERN_INFO "line = %d, rk616_hdmi_irq irq triggered.\n", __LINE__); + rk616_hdmi_work(); + } + } return IRQ_HANDLED; } -#endif + static int __devinit rk616_hdmi_probe (struct platform_device *pdev) { int ret; struct rk616_hdmi *rk616_hdmi; - - struct mfd_rk616 *rk616 = dev_get_drvdata(pdev->dev.parent); - if(!rk616) - { - dev_err(&pdev->dev,"null mfd device rk616!\n"); - return -ENODEV; - } + struct resource __maybe_unused *mem; + struct resource __maybe_unused *res; rk616_hdmi = devm_kzalloc(&pdev->dev, sizeof(*rk616_hdmi), GFP_KERNEL); if(!rk616_hdmi) @@ -233,7 +219,18 @@ static int __devinit rk616_hdmi_probe (struct platform_device *pdev) return -ENOMEM; } hdmi = &rk616_hdmi->g_hdmi; - rk616_hdmi->rk616_drv = rk616; + +#ifdef CONFIG_ARCH_RK3026 + rk616_hdmi->rk616_drv = NULL; +#else + rk616_hdmi->rk616_drv = dev_get_drvdata(pdev->dev.parent); + if(!(rk616_hdmi->rk616_drv)) + { + dev_err(&pdev->dev,"null mfd device rk616!\n"); + return -ENODEV; + } + +#endif hdmi->dev = &pdev->dev; platform_set_drvdata(pdev, hdmi); @@ -251,7 +248,6 @@ static int __devinit rk616_hdmi_probe (struct platform_device *pdev) hdmi->xscale = 100; hdmi->yscale = 100; - ret = rk616_hdmi_initial(); hdmi_sys_init(); @@ -265,7 +261,6 @@ static int __devinit rk616_hdmi_probe (struct platform_device *pdev) register_early_suspend(&hdmi->early_suspend); #endif - hdmi_register_display_sysfs(hdmi, NULL); #ifdef CONFIG_SWITCH hdmi->switch_hdmi.name="hdmi"; switch_dev_register(&(hdmi->switch_hdmi)); @@ -277,39 +272,102 @@ static int __devinit rk616_hdmi_probe (struct platform_device *pdev) INIT_DELAYED_WORK(&rk616_hdmi->rk616_delay_work, rk616_delay_work_func); /* get the IRQ */ - if(rk616->pdata->hdmi_irq != INVALID_GPIO) - { - INIT_WORK(&rk616_hdmi->rk616_irq_work_struct, rk616_irq_work_func); - ret = gpio_request(rk616->pdata->hdmi_irq,"rk616_hdmi_irq"); - if(ret < 0) - { - dev_err(hdmi->dev,"request gpio for rk616 hdmi irq fail\n"); - } - gpio_direction_input(rk616->pdata->hdmi_irq); - hdmi->irq = gpio_to_irq(rk616->pdata->hdmi_irq); - if(hdmi->irq <= 0) { - dev_err(hdmi->dev, "failed to get hdmi irq resource (%d).\n", hdmi->irq); - ret = -ENXIO; - goto err1; - } - - /* request the IRQ */ + // if(rk616->pdata->hdmi_irq != INVALID_GPIO) + +#ifdef CONFIG_ARCH_RK3026 + hdmi->hclk = clk_get(NULL,"pclk_hdmi"); + if(IS_ERR(hdmi->hclk)) { + dev_err(hdmi->dev, "Unable to get hdmi hclk\n"); + ret = -ENXIO; + goto err0; + } + clk_enable(hdmi->hclk); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(hdmi->dev, "Unable to get register resource\n"); + ret = -ENXIO; + goto err0; + } + hdmi->regbase_phy = res->start; + hdmi->regsize_phy = (res->end - res->start) + 1; + mem = request_mem_region(res->start, (res->end - res->start) + 1, pdev->name); + if (!mem) { + dev_err(hdmi->dev, "failed to request mem region for hdmi\n"); + ret = -ENOENT; + goto err0; + } + + printk("res->start = 0x%x\n, xhc-------res->end = 0x%x\n", res->start, res->end); + hdmi->regbase = (int)ioremap(res->start, (res->end - res->start) + 1); + if (!hdmi->regbase) { + dev_err(hdmi->dev, "cannot ioremap registers\n"); + ret = -ENXIO; + goto err1; + } + + // rk30_mux_api_set(GPIO0A7_I2C3_SDA_HDMI_DDCSDA_NAME, GPIO0A_HDMI_DDCSDA); + // rk30_mux_api_set(GPIO0A6_I2C3_SCL_HDMI_DDCSCL_NAME, GPIO0A_HDMI_DDCSCL); + // rk30_mux_api_set(GPIO0B7_HDMI_HOTPLUGIN_NAME, GPIO0B_HDMI_HOTPLUGIN); + iomux_set(HDMI_DDCSDA); + iomux_set(HDMI_DDCSCL); + iomux_set(HDMI_HOTPLUGIN); + + ret = rk616_hdmi_initial(); + /* get the IRQ */ + hdmi->irq = platform_get_irq(pdev, 0); + if(hdmi->irq <= 0) { + dev_err(hdmi->dev, "failed to get hdmi irq resource (%d).\n", hdmi->irq); + hdmi->irq = 0; + } else { + /* request the IRQ */ + ret = request_irq(hdmi->irq, rk616_hdmi_irq, 0, dev_name(&pdev->dev), hdmi); + if (ret) { + dev_err(hdmi->dev, "hdmi request_irq failed (%d).\n", ret); + goto err1; + } + } +#else + ret = rk616_hdmi_initial(); + if(rk616_hdmi->rk616_drv->pdata->hdmi_irq != INVALID_GPIO) { + INIT_WORK(&rk616_hdmi->rk616_irq_work_struct, rk616_irq_work_func); + ret = gpio_request(rk616_hdmi->rk616_drv->pdata->hdmi_irq,"rk616_hdmi_irq"); + if(ret < 0) { + dev_err(hdmi->dev,"request gpio for rk616 hdmi irq fail\n"); + } + gpio_direction_input(rk616_hdmi->rk616_drv->pdata->hdmi_irq); + hdmi->irq = gpio_to_irq(rk616_hdmi->rk616_drv->pdata->hdmi_irq); + if(hdmi->irq <= 0) { + dev_err(hdmi->dev, "failed to get hdmi irq resource (%d).\n", hdmi->irq); + ret = -ENXIO; + goto err1; + } + + /* request the IRQ */ ret = request_irq(hdmi->irq, rk616_hdmi_irq, IRQF_TRIGGER_LOW, dev_name(&pdev->dev), &rk616_hdmi->rk616_irq_work_struct); - if (ret) - { - dev_err(hdmi->dev, "hdmi request_irq failed (%d).\n", ret); - goto err1; - } - } else { - + if (ret) { + dev_err(hdmi->dev, "hdmi request_irq failed (%d).\n", ret); + goto err1; + } + } else { /* use roll polling method */ - hdmi->irq = 0; + hdmi->irq = 0; } + +#endif + hdmi_register_display_sysfs(hdmi, NULL); + #if defined(CONFIG_DEBUG_FS) - if(rk616->debugfs_dir) - { - debugfs_create_file("hdmi", S_IRUSR,rk616->debugfs_dir,rk616,&rk616_hdmi_reg_fops); - } + if(rk616_hdmi->rk616_drv && rk616_hdmi->rk616_drv->debugfs_dir) { + debugfs_create_file("hdmi", S_IRUSR, rk616_hdmi->rk616_drv->debugfs_dir, rk616_hdmi->rk616_drv, &rk616_hdmi_reg_fops); + } else { + rk616_hdmi->debugfs_dir = debugfs_create_dir("rk616", NULL); + if (IS_ERR(rk616_hdmi->debugfs_dir)) { + dev_err(hdmi->dev,"failed to create debugfs dir for rk616!\n"); + } else { + debugfs_create_file("hdmi", S_IRUSR, rk616_hdmi->debugfs_dir, rk616_hdmi, &rk616_hdmi_reg_fops); + } + } #endif // rk616_delay_work_func(NULL); queue_delayed_work(hdmi->workqueue, &rk616_hdmi->rk616_delay_work, msecs_to_jiffies(0)); diff --git a/drivers/video/rockchip/hdmi/chips/rk616/rk616_hdmi.h b/drivers/video/rockchip/hdmi/chips/rk616/rk616_hdmi.h index c2a807abfe98..2d033fa6f330 100755 --- a/drivers/video/rockchip/hdmi/chips/rk616/rk616_hdmi.h +++ b/drivers/video/rockchip/hdmi/chips/rk616/rk616_hdmi.h @@ -32,6 +32,7 @@ struct rk616_hdmi { struct delayed_work rk616_delay_work; struct work_struct rk616_irq_work_struct; struct mfd_rk616 *rk616_drv; + struct dentry *debugfs_dir; }; #endif /* __RK30_HDMI_H__ */ diff --git a/drivers/video/rockchip/hdmi/chips/rk616/rk616_hdmi_hw.c b/drivers/video/rockchip/hdmi/chips/rk616/rk616_hdmi_hw.c index ad0c16f35169..76db26bcd074 100755 --- a/drivers/video/rockchip/hdmi/chips/rk616/rk616_hdmi_hw.c +++ b/drivers/video/rockchip/hdmi/chips/rk616/rk616_hdmi_hw.c @@ -7,14 +7,13 @@ // static char edid_result = 0; - +#ifndef CONFIG_ARCH_RK3026 static int rk616_set_polarity(struct mfd_rk616 * rk616, int vic) { u32 val; int ret; u32 hdmi_polarity_mask = (3<<14); - // printk("----------xhc---------vic = %d\n", vic); switch(vic) { @@ -48,7 +47,6 @@ static int rk616_hdmi_set_vif(rk_screen * screen,bool connect) struct rk616_hdmi *rk616_hdmi; rk616_hdmi = container_of(hdmi, struct rk616_hdmi, g_hdmi); - if (connect) rk616_set_polarity(rk616_hdmi->rk616_drv, hdmi->vic); @@ -60,15 +58,18 @@ static int rk616_hdmi_init_pol_set(struct mfd_rk616 * rk616,int pol) { u32 val; int ret; - ret = rk616->read_dev(rk616,CRU_CFGMISC_CON,&val); - if(pol) - val &= 0xffffffdf; - else - val |= 0x20; - ret = rk616->write_dev(rk616,CRU_CFGMISC_CON,&val); + int int_pol_mask = (1 << 5); + + if (pol) + val = 0x0; + else + val = 0x20; + ret = rk616->write_dev_bits(rk616, CRU_CFGMISC_CON, int_pol_mask, &val); return 0; } +#endif + static inline void delay100us(void) { msleep(1); @@ -358,7 +359,6 @@ static int rk616_hdmi_config_video(struct hdmi_video_para *vpara) value = mode->vsync_len; hdmi_writel(VIDEO_EXT_VDURATION, value & 0xFF); #endif - //rk616_set_polarity(rk616_hdmi->rk616_drv, vpara->vic); if(vpara->output_mode == OUTPUT_HDMI) { rk616_hdmi_config_avi(vpara->vic, vpara->output_color); @@ -368,19 +368,15 @@ static int rk616_hdmi_config_video(struct hdmi_video_para *vpara) hdmi_dbg(hdmi->dev, "[%s] sucess output DVI.\n", __FUNCTION__); } -#if 1 - hdmi_writel(0xed, 0x0f); - hdmi_writel(0xe7, 0x96); -#else - if(hdmi->tmdsclk >= 148500000) { - hdmi_writel(0xed, 0xc); - hdmi_writel(0xe7, 0x78); - } - else { - hdmi_writel(0xed, 0x3); - hdmi_writel(0xe7, 0x1e); - } -#endif + // if(rk616_hdmi->rk616_drv) { + if (hdmi->set_vif) { + hdmi_writel(0xed, 0x0f); + hdmi_writel(0xe7, 0x96); + } else { // rk3028a + hdmi_writel(0xed, 0x1e); + hdmi_writel(0xe7, 0x2c); + hdmi_writel(0xe8, 0x01); + } return 0; } @@ -520,6 +516,7 @@ void rk616_hdmi_work(void) u32 interrupt = 0; // int value = 0; + hdmi_readl(INTERRUPT_STATUS1,&interrupt); if(interrupt){ hdmi_writel(INTERRUPT_STATUS1, interrupt); @@ -576,11 +573,16 @@ int rk616_hdmi_initial(void) hdmi->config_audio = rk616_hdmi_config_audio; hdmi->detect_hotplug = rk616_hdmi_detect_hotplug; hdmi->read_edid = rk616_hdmi_read_edid; - hdmi->set_vif = rk616_hdmi_set_vif; - - rk616_hdmi_reset(); +#ifdef CONFIG_ARCH_RK3026 + rk3028_hdmi_reset_pclk(); + rk616_hdmi_reset(); +#else + hdmi->set_vif = rk616_hdmi_set_vif; + rk616_hdmi_reset(); rk616_hdmi_init_pol_set(rk616_hdmi->rk616_drv, 0); +#endif + if(hdmi->hdcp_power_on_cb) rc = hdmi->hdcp_power_on_cb(); diff --git a/drivers/video/rockchip/hdmi/chips/rk616/rk616_hdmi_hw.h b/drivers/video/rockchip/hdmi/chips/rk616/rk616_hdmi_hw.h index c3b98ebd3e12..c998933c0bb3 100755 --- a/drivers/video/rockchip/hdmi/chips/rk616/rk616_hdmi_hw.h +++ b/drivers/video/rockchip/hdmi/chips/rk616/rk616_hdmi_hw.h @@ -285,6 +285,7 @@ enum { #define PHY_PRE_DIV_RATIO 0xed #define v_PRE_DIV_RATIO(n) (n&1f) +#ifndef CONFIG_ARCH_RK3026 static inline int hdmi_readl(u16 offset, u32 *val) { int ret; @@ -314,6 +315,37 @@ static inline int hdmi_msk_reg(u16 offset, u32 msk, u32 val) ret = rk616_hdmi->rk616_drv->write_dev_bits(rk616_hdmi->rk616_drv, (RK616_HDMI_BASE + ((offset)<<2)), msk, &val); return ret; } +#else + +static inline int hdmi_readl(u16 offset, u32 *val) +{ + int ret = 0; + *val = readl_relaxed(hdmi->regbase + (offset) * 0x04); + return ret; +} + +static inline int hdmi_writel(u16 offset, u32 val) +{ + int ret = 0; + writel_relaxed(val, hdmi->regbase + (offset) * 0x04); + return ret; +} + +static inline int hdmi_msk_reg(u16 offset, u32 msk, u32 val) +{ + int ret = 0; + u32 temp; + temp = readl_relaxed(hdmi->regbase + (offset) * 0x04) & (0xFF - (msk)); + writel_relaxed(temp | ( (val) & (msk) ), hdmi->regbase + (offset) * 0x04); + return ret; +} +static inline void rk3028_hdmi_reset_pclk(void) +{ + writel_relaxed(0x00010001,RK2928_CRU_BASE+ 0x128); + msleep(100); + writel_relaxed(0x00010000, RK2928_CRU_BASE + 0x128); +} +#endif extern int rk616_hdmi_initial(void); extern void rk616_hdmi_work(void);