diff options
Diffstat (limited to 'drivers/video')
120 files changed, 6463 insertions, 4696 deletions
diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c index a425d65d5ba2..fa44fbed397d 100644 --- a/drivers/video/68328fb.c +++ b/drivers/video/68328fb.c @@ -400,7 +400,7 @@ static int mc68x328fb_mmap(struct fb_info *info, struct vm_area_struct *vma) #ifndef MMU /* this is uClinux (no MMU) specific code */ - vma->vm_flags |= VM_RESERVED; + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; vma->vm_start = videomemory; return 0; diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 20c33c42600a..d08d7998a4aa 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -2139,21 +2139,6 @@ config FB_UDL mplayer -vo fbdev. Supports all USB 2.0 era DisplayLink devices. To compile as a module, choose M here: the module name is udlfb. -config FB_PNX4008_DUM - tristate "Display Update Module support on Philips PNX4008 board" - depends on FB && ARCH_PNX4008 - ---help--- - Say Y here to enable support for PNX4008 Display Update Module (DUM) - -config FB_PNX4008_DUM_RGB - tristate "RGB Framebuffer support on Philips PNX4008 board" - depends on FB_PNX4008_DUM - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Say Y here to enable support for PNX4008 RGB Framebuffer - config FB_IBM_GXT4500 tristate "Framebuffer support for IBM GXT4500P adaptor" depends on FB && PPC diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 194035986af2..23e948ebfab8 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -127,8 +127,6 @@ obj-$(CONFIG_FB_S3C) += s3c-fb.o obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o -obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/ -obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o obj-$(CONFIG_FB_PS3) += ps3fb.o obj-$(CONFIG_FB_SM501) += sm501fb.o diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index 887df9d81422..7fa1bf823729 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -949,7 +949,6 @@ static int round_down_bpp = 1; /* for mode probing */ static int amifb_ilbm = 0; /* interleaved or normal bitplanes */ -static int amifb_inverse = 0; static u32 amifb_hfmin __initdata; /* monitor hfreq lower limit (Hz) */ static u32 amifb_hfmax __initdata; /* monitor hfreq upper limit (Hz) */ @@ -2355,7 +2354,6 @@ static int __init amifb_setup(char *options) if (!*this_opt) continue; if (!strcmp(this_opt, "inverse")) { - amifb_inverse = 1; fb_invert_cmaps(); } else if (!strcmp(this_opt, "ilbm")) amifb_ilbm = 1; diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c index a1d58e9d3073..4659d5da6ff8 100644 --- a/drivers/video/arcfb.c +++ b/drivers/video/arcfb.c @@ -552,6 +552,7 @@ static int __devinit arcfb_probe(struct platform_device *dev) "arcfb", info)) { printk(KERN_INFO "arcfb: Failed req IRQ %d\n", par->irq); + retval = -EBUSY; goto err1; } } diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 15055395cd95..94cac9f9919f 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -931,8 +931,10 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) } info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); - if (!info->screen_base) + if (!info->screen_base) { + ret = -ENOMEM; goto release_intmem; + } /* * Don't clear the framebuffer -- someone may have set @@ -960,6 +962,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len); if (!sinfo->mmio) { dev_err(dev, "cannot map LCDC registers\n"); + ret = -ENOMEM; goto release_mem; } diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 747442d2c0f6..0fefa84ed9ae 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -149,7 +149,7 @@ enum { }; /* Must match above enum */ -static const char *r128_family[] __devinitdata = { +static char * const r128_family[] __devinitconst = { "AGP", "PCI", "PRO AGP", diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 3f2e8c13f1ca..868932f904ef 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -1942,8 +1942,7 @@ static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma) off = vma->vm_pgoff << PAGE_SHIFT; size = vma->vm_end - vma->vm_start; - /* To stop the swapper from even considering these pages. */ - vma->vm_flags |= (VM_IO | VM_RESERVED); + /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */ if (((vma->vm_pgoff == 0) && (size == info->fix.smem_len)) || ((off == info->fix.smem_len) && (size == PAGE_SIZE))) diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index f49181c73113..b7ec34c57f46 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -11,6 +11,7 @@ #include <linux/init.h> #include <linux/kernel.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/fb.h> @@ -31,57 +32,26 @@ struct pm860x_backlight_data { int port; int pwm; int iset; + int reg_duty_cycle; + int reg_always_on; + int reg_current; }; -static inline int wled_a(int port) -{ - int ret; - - ret = ((port - PM8606_BACKLIGHT1) << 1) + 2; - return ret; -} - -static inline int wled_b(int port) -{ - int ret; - - ret = ((port - PM8606_BACKLIGHT1) << 1) + 3; - return ret; -} - -/* WLED2 & WLED3 share the same IDC */ -static inline int wled_idc(int port) -{ - int ret; - - switch (port) { - case PM8606_BACKLIGHT1: - case PM8606_BACKLIGHT2: - ret = ((port - PM8606_BACKLIGHT1) << 1) + 3; - break; - case PM8606_BACKLIGHT3: - default: - ret = ((port - PM8606_BACKLIGHT2) << 1) + 3; - break; - } - return ret; -} - static int backlight_power_set(struct pm860x_chip *chip, int port, int on) { int ret = -EINVAL; switch (port) { - case PM8606_BACKLIGHT1: + case 0: ret = on ? pm8606_osc_enable(chip, WLED1_DUTY) : pm8606_osc_disable(chip, WLED1_DUTY); break; - case PM8606_BACKLIGHT2: + case 1: ret = on ? pm8606_osc_enable(chip, WLED2_DUTY) : pm8606_osc_disable(chip, WLED2_DUTY); break; - case PM8606_BACKLIGHT3: + case 2: ret = on ? pm8606_osc_enable(chip, WLED3_DUTY) : pm8606_osc_disable(chip, WLED3_DUTY); break; @@ -104,13 +74,13 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness) if (brightness) backlight_power_set(chip, data->port, 1); - ret = pm860x_reg_write(data->i2c, wled_a(data->port), value); + ret = pm860x_reg_write(data->i2c, data->reg_duty_cycle, value); if (ret < 0) goto out; if ((data->current_brightness == 0) && brightness) { if (data->iset) { - ret = pm860x_set_bits(data->i2c, wled_idc(data->port), + ret = pm860x_set_bits(data->i2c, data->reg_current, CURRENT_BITMASK, data->iset); if (ret < 0) goto out; @@ -123,17 +93,17 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness) } if (brightness == MAX_BRIGHTNESS) { /* set WLED_ON bit as 100% */ - ret = pm860x_set_bits(data->i2c, wled_b(data->port), + ret = pm860x_set_bits(data->i2c, data->reg_always_on, PM8606_WLED_ON, PM8606_WLED_ON); } } else { if (brightness == MAX_BRIGHTNESS) { /* set WLED_ON bit as 100% */ - ret = pm860x_set_bits(data->i2c, wled_b(data->port), + ret = pm860x_set_bits(data->i2c, data->reg_always_on, PM8606_WLED_ON, PM8606_WLED_ON); } else { /* clear WLED_ON bit since it's not 100% */ - ret = pm860x_set_bits(data->i2c, wled_b(data->port), + ret = pm860x_set_bits(data->i2c, data->reg_always_on, PM8606_WLED_ON, 0); } } @@ -174,7 +144,7 @@ static int pm860x_backlight_get_brightness(struct backlight_device *bl) struct pm860x_chip *chip = data->chip; int ret; - ret = pm860x_reg_read(data->i2c, wled_a(data->port)); + ret = pm860x_reg_read(data->i2c, data->reg_duty_cycle); if (ret < 0) goto out; data->current_brightness = ret; @@ -190,45 +160,85 @@ static const struct backlight_ops pm860x_backlight_ops = { .get_brightness = pm860x_backlight_get_brightness, }; +#ifdef CONFIG_OF +static int pm860x_backlight_dt_init(struct platform_device *pdev, + struct pm860x_backlight_data *data, + char *name) +{ + struct device_node *nproot = pdev->dev.parent->of_node, *np; + int iset = 0; + if (!nproot) + return -ENODEV; + nproot = of_find_node_by_name(nproot, "backlights"); + if (!nproot) { + dev_err(&pdev->dev, "failed to find backlights node\n"); + return -ENODEV; + } + for_each_child_of_node(nproot, np) { + if (!of_node_cmp(np->name, name)) { + of_property_read_u32(np, "marvell,88pm860x-iset", + &iset); + data->iset = PM8606_WLED_CURRENT(iset); + of_property_read_u32(np, "marvell,88pm860x-pwm", + &data->pwm); + break; + } + } + return 0; +} +#else +#define pm860x_backlight_dt_init(x, y, z) (-1) +#endif + static int pm860x_backlight_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct pm860x_backlight_pdata *pdata = NULL; + struct pm860x_backlight_pdata *pdata = pdev->dev.platform_data; struct pm860x_backlight_data *data; struct backlight_device *bl; struct resource *res; struct backlight_properties props; char name[MFD_NAME_SIZE]; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource!\n"); - return -EINVAL; - } - - pdata = pdev->dev.platform_data; - if (pdata == NULL) { - dev_err(&pdev->dev, "platform data isn't assigned to " - "backlight\n"); - return -EINVAL; - } + int ret = 0; data = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_backlight_data), GFP_KERNEL); if (data == NULL) return -ENOMEM; - strncpy(name, res->name, MFD_NAME_SIZE); + res = platform_get_resource_byname(pdev, IORESOURCE_REG, "duty cycle"); + if (!res) { + dev_err(&pdev->dev, "No REG resource for duty cycle\n"); + ret = -ENXIO; + goto out; + } + data->reg_duty_cycle = res->start; + res = platform_get_resource_byname(pdev, IORESOURCE_REG, "always on"); + if (!res) { + dev_err(&pdev->dev, "No REG resorce for always on\n"); + ret = -ENXIO; + goto out; + } + data->reg_always_on = res->start; + res = platform_get_resource_byname(pdev, IORESOURCE_REG, "current"); + if (!res) { + dev_err(&pdev->dev, "No REG resource for current\n"); + ret = -ENXIO; + goto out; + } + data->reg_current = res->start; + + memset(name, 0, MFD_NAME_SIZE); + sprintf(name, "backlight-%d", pdev->id); + data->port = pdev->id; data->chip = chip; data->i2c = (chip->id == CHIP_PM8606) ? chip->client \ : chip->companion; data->current_brightness = MAX_BRIGHTNESS; - data->pwm = pdata->pwm; - data->iset = pdata->iset; - data->port = pdata->flags; - if (data->port < 0) { - dev_err(&pdev->dev, "wrong platform data is assigned"); - return -EINVAL; + if (pm860x_backlight_dt_init(pdev, data, name)) { + if (pdata) { + data->pwm = pdata->pwm; + data->iset = pdata->iset; + } } memset(&props, 0, sizeof(struct backlight_properties)); @@ -247,12 +257,14 @@ static int pm860x_backlight_probe(struct platform_device *pdev) /* read current backlight */ ret = pm860x_backlight_get_brightness(bl); if (ret < 0) - goto out; + goto out_brt; backlight_update_status(bl); return 0; -out: +out_brt: backlight_device_unregister(bl); +out: + devm_kfree(&pdev->dev, data); return ret; } diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index cf282763a8dc..765a945f8ea1 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -60,7 +60,8 @@ config LCD_LTV350QV The LTV350QV panel is present on all ATSTK1000 boards. config LCD_ILI9320 - tristate + tristate "ILI Technology ILI9320 controller support" + depends on SPI help If you have a panel based on the ILI9320 controller chip then say y to include a power driver for it. @@ -229,13 +230,6 @@ config BACKLIGHT_HP700 If you have an HP Jornada 700 series, say Y to include backlight control driver. -config BACKLIGHT_PROGEAR - tristate "Frontpath ProGear Backlight Driver" - depends on PCI && X86 - help - If you have a Frontpath ProGear say Y to enable the - backlight driver. - config BACKLIGHT_CARILLO_RANCH tristate "Intel Carillo Ranch Backlight Driver" depends on LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578 @@ -352,6 +346,22 @@ config BACKLIGHT_AAT2870 If you have a AnalogicTech AAT2870 say Y to enable the backlight driver. +config BACKLIGHT_LM3630 + tristate "Backlight Driver for LM3630" + depends on BACKLIGHT_CLASS_DEVICE && I2C + select REGMAP_I2C + help + This supports TI LM3630 Backlight Driver + +config BACKLIGHT_LM3639 + tristate "Backlight Driver for LM3639" + depends on BACKLIGHT_CLASS_DEVICE && I2C + select REGMAP_I2C + select NEW_LEDS + select LEDS_CLASS + help + This supports TI LM3639 Backlight + 1.5A Flash LED Driver + config BACKLIGHT_LP855X tristate "Backlight driver for TI LP855X" depends on BACKLIGHT_CLASS_DEVICE && I2C @@ -373,6 +383,13 @@ config BACKLIGHT_PANDORA If you have a Pandora console, say Y to enable the backlight driver. +config BACKLIGHT_TPS65217 + tristate "TPS65217 Backlight" + depends on BACKLIGHT_CLASS_DEVICE && MFD_TPS65217 + help + If you have a Texas Instruments TPS65217 say Y to enable the + backlight driver. + endif # BACKLIGHT_CLASS_DEVICE endif # BACKLIGHT_LCD_SUPPORT diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index a2ac9cfbaf6b..e7ce7291635d 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -23,10 +23,11 @@ obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o +obj-$(CONFIG_BACKLIGHT_LM3630) += lm3630_bl.o +obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o -obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o @@ -43,3 +44,4 @@ obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o obj-$(CONFIG_BACKLIGHT_AAT2870) += aat2870_bl.o obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o +obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o diff --git a/drivers/video/backlight/da9052_bl.c b/drivers/video/backlight/da9052_bl.c index b628d68f5162..ac196181fe45 100644 --- a/drivers/video/backlight/da9052_bl.c +++ b/drivers/video/backlight/da9052_bl.c @@ -72,7 +72,7 @@ static int da9052_adjust_wled_brightness(struct da9052_bl *wleds) if (ret < 0) return ret; - msleep(10); + usleep_range(10000, 11000); if (wleds->brightness) { ret = da9052_reg_write(wleds->da9052, wled_bank[wleds->led_reg], @@ -129,7 +129,6 @@ static int da9052_backlight_probe(struct platform_device *pdev) &da9052_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "Failed to register backlight\n"); - devm_kfree(&pdev->dev, wleds); return PTR_ERR(bl); } @@ -149,7 +148,6 @@ static int da9052_backlight_remove(struct platform_device *pdev) wleds->state = DA9052_WLEDS_OFF; da9052_adjust_wled_brightness(wleds); backlight_device_unregister(bl); - devm_kfree(&pdev->dev, wleds); return 0; } diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c index 72dd5556a35b..6c5ed6b242cc 100644 --- a/drivers/video/backlight/kb3886_bl.c +++ b/drivers/video/backlight/kb3886_bl.c @@ -34,9 +34,9 @@ static void kb3886_bl_set_intensity(int intensity) mutex_lock(&bl_mutex); intensity = intensity&0xff; outb(KB3886_ADC_DAC_PWM, KB3886_PARENT); - msleep(10); + usleep_range(10000, 11000); outb(KB3886_PWM0_WRITE, KB3886_IO); - msleep(10); + usleep_range(10000, 11000); outb(intensity, KB3886_IO); mutex_unlock(&bl_mutex); } diff --git a/drivers/video/backlight/lm3630_bl.c b/drivers/video/backlight/lm3630_bl.c new file mode 100644 index 000000000000..dc191441796f --- /dev/null +++ b/drivers/video/backlight/lm3630_bl.c @@ -0,0 +1,475 @@ +/* +* Simple driver for Texas Instruments LM3630 Backlight driver chip +* Copyright (C) 2012 Texas Instruments +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +*/ +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/backlight.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/uaccess.h> +#include <linux/interrupt.h> +#include <linux/regmap.h> +#include <linux/platform_data/lm3630_bl.h> + +#define REG_CTRL 0x00 +#define REG_CONFIG 0x01 +#define REG_BRT_A 0x03 +#define REG_BRT_B 0x04 +#define REG_INT_STATUS 0x09 +#define REG_INT_EN 0x0A +#define REG_FAULT 0x0B +#define REG_PWM_OUTLOW 0x12 +#define REG_PWM_OUTHIGH 0x13 +#define REG_MAX 0x1F + +#define INT_DEBOUNCE_MSEC 10 + +enum lm3630_leds { + BLED_ALL = 0, + BLED_1, + BLED_2 +}; + +static const char *bled_name[] = { + [BLED_ALL] = "lm3630_bled", /*Bank1 controls all string */ + [BLED_1] = "lm3630_bled1", /*Bank1 controls bled1 */ + [BLED_2] = "lm3630_bled2", /*Bank1 or 2 controls bled2 */ +}; + +struct lm3630_chip_data { + struct device *dev; + struct delayed_work work; + int irq; + struct workqueue_struct *irqthread; + struct lm3630_platform_data *pdata; + struct backlight_device *bled1; + struct backlight_device *bled2; + struct regmap *regmap; +}; + +/* initialize chip */ +static int __devinit lm3630_chip_init(struct lm3630_chip_data *pchip) +{ + int ret; + unsigned int reg_val; + struct lm3630_platform_data *pdata = pchip->pdata; + + /*pwm control */ + reg_val = ((pdata->pwm_active & 0x01) << 2) | (pdata->pwm_ctrl & 0x03); + ret = regmap_update_bits(pchip->regmap, REG_CONFIG, 0x07, reg_val); + if (ret < 0) + goto out; + + /* bank control */ + reg_val = ((pdata->bank_b_ctrl & 0x01) << 1) | + (pdata->bank_a_ctrl & 0x07); + ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x07, reg_val); + if (ret < 0) + goto out; + + ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00); + if (ret < 0) + goto out; + + /* set initial brightness */ + if (pdata->bank_a_ctrl != BANK_A_CTRL_DISABLE) { + ret = regmap_write(pchip->regmap, + REG_BRT_A, pdata->init_brt_led1); + if (ret < 0) + goto out; + } + + if (pdata->bank_b_ctrl != BANK_B_CTRL_DISABLE) { + ret = regmap_write(pchip->regmap, + REG_BRT_B, pdata->init_brt_led2); + if (ret < 0) + goto out; + } + return ret; + +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return ret; +} + +/* interrupt handling */ +static void lm3630_delayed_func(struct work_struct *work) +{ + int ret; + unsigned int reg_val; + struct lm3630_chip_data *pchip; + + pchip = container_of(work, struct lm3630_chip_data, work.work); + + ret = regmap_read(pchip->regmap, REG_INT_STATUS, ®_val); + if (ret < 0) { + dev_err(pchip->dev, + "i2c failed to access REG_INT_STATUS Register\n"); + return; + } + + dev_info(pchip->dev, "REG_INT_STATUS Register is 0x%x\n", reg_val); +} + +static irqreturn_t lm3630_isr_func(int irq, void *chip) +{ + int ret; + struct lm3630_chip_data *pchip = chip; + unsigned long delay = msecs_to_jiffies(INT_DEBOUNCE_MSEC); + + queue_delayed_work(pchip->irqthread, &pchip->work, delay); + + ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00); + if (ret < 0) + goto out; + + return IRQ_HANDLED; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return IRQ_HANDLED; +} + +static int lm3630_intr_config(struct lm3630_chip_data *pchip) +{ + INIT_DELAYED_WORK(&pchip->work, lm3630_delayed_func); + pchip->irqthread = create_singlethread_workqueue("lm3630-irqthd"); + if (!pchip->irqthread) { + dev_err(pchip->dev, "create irq thread fail...\n"); + return -1; + } + if (request_threaded_irq + (pchip->irq, NULL, lm3630_isr_func, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lm3630_irq", pchip)) { + dev_err(pchip->dev, "request threaded irq fail..\n"); + return -1; + } + return 0; +} + +static bool +set_intensity(struct backlight_device *bl, struct lm3630_chip_data *pchip) +{ + if (!pchip->pdata->pwm_set_intensity) + return false; + pchip->pdata->pwm_set_intensity(bl->props.brightness - 1, + pchip->pdata->pwm_period); + return true; +} + +/* update and get brightness */ +static int lm3630_bank_a_update_status(struct backlight_device *bl) +{ + int ret; + struct lm3630_chip_data *pchip = bl_get_data(bl); + enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; + + /* brightness 0 means disable */ + if (!bl->props.brightness) { + ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x04, 0x00); + if (ret < 0) + goto out; + return bl->props.brightness; + } + + /* pwm control */ + if (pwm_ctrl == PWM_CTRL_BANK_A || pwm_ctrl == PWM_CTRL_BANK_ALL) { + if (!set_intensity(bl, pchip)) + dev_err(pchip->dev, "No pwm control func. in plat-data\n"); + } else { + + /* i2c control */ + ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00); + if (ret < 0) + goto out; + mdelay(1); + ret = regmap_write(pchip->regmap, + REG_BRT_A, bl->props.brightness - 1); + if (ret < 0) + goto out; + } + return bl->props.brightness; +out: + dev_err(pchip->dev, "i2c failed to access REG_CTRL\n"); + return bl->props.brightness; +} + +static int lm3630_bank_a_get_brightness(struct backlight_device *bl) +{ + unsigned int reg_val; + int brightness, ret; + struct lm3630_chip_data *pchip = bl_get_data(bl); + enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; + + if (pwm_ctrl == PWM_CTRL_BANK_A || pwm_ctrl == PWM_CTRL_BANK_ALL) { + ret = regmap_read(pchip->regmap, REG_PWM_OUTHIGH, ®_val); + if (ret < 0) + goto out; + brightness = reg_val & 0x01; + ret = regmap_read(pchip->regmap, REG_PWM_OUTLOW, ®_val); + if (ret < 0) + goto out; + brightness = ((brightness << 8) | reg_val) + 1; + } else { + ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00); + if (ret < 0) + goto out; + mdelay(1); + ret = regmap_read(pchip->regmap, REG_BRT_A, ®_val); + if (ret < 0) + goto out; + brightness = reg_val + 1; + } + bl->props.brightness = brightness; + return bl->props.brightness; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return 0; +} + +static const struct backlight_ops lm3630_bank_a_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = lm3630_bank_a_update_status, + .get_brightness = lm3630_bank_a_get_brightness, +}; + +static int lm3630_bank_b_update_status(struct backlight_device *bl) +{ + int ret; + struct lm3630_chip_data *pchip = bl_get_data(bl); + enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; + + if (pwm_ctrl == PWM_CTRL_BANK_B || pwm_ctrl == PWM_CTRL_BANK_ALL) { + if (!set_intensity(bl, pchip)) + dev_err(pchip->dev, + "no pwm control func. in plat-data\n"); + } else { + ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00); + if (ret < 0) + goto out; + mdelay(1); + ret = regmap_write(pchip->regmap, + REG_BRT_B, bl->props.brightness - 1); + } + return bl->props.brightness; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return bl->props.brightness; +} + +static int lm3630_bank_b_get_brightness(struct backlight_device *bl) +{ + unsigned int reg_val; + int brightness, ret; + struct lm3630_chip_data *pchip = bl_get_data(bl); + enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; + + if (pwm_ctrl == PWM_CTRL_BANK_B || pwm_ctrl == PWM_CTRL_BANK_ALL) { + ret = regmap_read(pchip->regmap, REG_PWM_OUTHIGH, ®_val); + if (ret < 0) + goto out; + brightness = reg_val & 0x01; + ret = regmap_read(pchip->regmap, REG_PWM_OUTLOW, ®_val); + if (ret < 0) + goto out; + brightness = ((brightness << 8) | reg_val) + 1; + } else { + ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00); + if (ret < 0) + goto out; + mdelay(1); + ret = regmap_read(pchip->regmap, REG_BRT_B, ®_val); + if (ret < 0) + goto out; + brightness = reg_val + 1; + } + bl->props.brightness = brightness; + + return bl->props.brightness; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return bl->props.brightness; +} + +static const struct backlight_ops lm3630_bank_b_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = lm3630_bank_b_update_status, + .get_brightness = lm3630_bank_b_get_brightness, +}; + +static int lm3630_backlight_register(struct lm3630_chip_data *pchip, + enum lm3630_leds ledno) +{ + const char *name = bled_name[ledno]; + struct backlight_properties props; + struct lm3630_platform_data *pdata = pchip->pdata; + + props.type = BACKLIGHT_RAW; + switch (ledno) { + case BLED_1: + case BLED_ALL: + props.brightness = pdata->init_brt_led1; + props.max_brightness = pdata->max_brt_led1; + pchip->bled1 = + backlight_device_register(name, pchip->dev, pchip, + &lm3630_bank_a_ops, &props); + if (IS_ERR(pchip->bled1)) + return -EIO; + break; + case BLED_2: + props.brightness = pdata->init_brt_led2; + props.max_brightness = pdata->max_brt_led2; + pchip->bled2 = + backlight_device_register(name, pchip->dev, pchip, + &lm3630_bank_b_ops, &props); + if (IS_ERR(pchip->bled2)) + return -EIO; + break; + } + return 0; +} + +static void lm3630_backlight_unregister(struct lm3630_chip_data *pchip) +{ + if (pchip->bled1) + backlight_device_unregister(pchip->bled1); + if (pchip->bled2) + backlight_device_unregister(pchip->bled2); +} + +static const struct regmap_config lm3630_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = REG_MAX, +}; + +static int __devinit lm3630_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct lm3630_platform_data *pdata = client->dev.platform_data; + struct lm3630_chip_data *pchip; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "fail : i2c functionality check...\n"); + return -EOPNOTSUPP; + } + + if (pdata == NULL) { + dev_err(&client->dev, "fail : no platform data.\n"); + return -ENODATA; + } + + pchip = devm_kzalloc(&client->dev, sizeof(struct lm3630_chip_data), + GFP_KERNEL); + if (!pchip) + return -ENOMEM; + pchip->pdata = pdata; + pchip->dev = &client->dev; + + pchip->regmap = devm_regmap_init_i2c(client, &lm3630_regmap); + if (IS_ERR(pchip->regmap)) { + ret = PTR_ERR(pchip->regmap); + dev_err(&client->dev, "fail : allocate register map: %d\n", + ret); + return ret; + } + i2c_set_clientdata(client, pchip); + + /* chip initialize */ + ret = lm3630_chip_init(pchip); + if (ret < 0) { + dev_err(&client->dev, "fail : init chip\n"); + goto err_chip_init; + } + + switch (pdata->bank_a_ctrl) { + case BANK_A_CTRL_ALL: + ret = lm3630_backlight_register(pchip, BLED_ALL); + pdata->bank_b_ctrl = BANK_B_CTRL_DISABLE; + break; + case BANK_A_CTRL_LED1: + ret = lm3630_backlight_register(pchip, BLED_1); + break; + case BANK_A_CTRL_LED2: + ret = lm3630_backlight_register(pchip, BLED_2); + pdata->bank_b_ctrl = BANK_B_CTRL_DISABLE; + break; + default: + break; + } + + if (ret < 0) + goto err_bl_reg; + + if (pdata->bank_b_ctrl && pchip->bled2 == NULL) { + ret = lm3630_backlight_register(pchip, BLED_2); + if (ret < 0) + goto err_bl_reg; + } + + /* interrupt enable : irq 0 is not allowed for lm3630 */ + pchip->irq = client->irq; + if (pchip->irq) + lm3630_intr_config(pchip); + + dev_info(&client->dev, "LM3630 backlight register OK.\n"); + return 0; + +err_bl_reg: + dev_err(&client->dev, "fail : backlight register.\n"); + lm3630_backlight_unregister(pchip); +err_chip_init: + return ret; +} + +static int __devexit lm3630_remove(struct i2c_client *client) +{ + int ret; + struct lm3630_chip_data *pchip = i2c_get_clientdata(client); + + ret = regmap_write(pchip->regmap, REG_BRT_A, 0); + if (ret < 0) + dev_err(pchip->dev, "i2c failed to access register\n"); + + ret = regmap_write(pchip->regmap, REG_BRT_B, 0); + if (ret < 0) + dev_err(pchip->dev, "i2c failed to access register\n"); + + lm3630_backlight_unregister(pchip); + if (pchip->irq) { + free_irq(pchip->irq, pchip); + flush_workqueue(pchip->irqthread); + destroy_workqueue(pchip->irqthread); + } + return 0; +} + +static const struct i2c_device_id lm3630_id[] = { + {LM3630_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, lm3630_id); + +static struct i2c_driver lm3630_i2c_driver = { + .driver = { + .name = LM3630_NAME, + }, + .probe = lm3630_probe, + .remove = __devexit_p(lm3630_remove), + .id_table = lm3630_id, +}; + +module_i2c_driver(lm3630_i2c_driver); + +MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630"); +MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>"); +MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/video/backlight/lm3639_bl.c b/drivers/video/backlight/lm3639_bl.c new file mode 100644 index 000000000000..585949b57055 --- /dev/null +++ b/drivers/video/backlight/lm3639_bl.c @@ -0,0 +1,437 @@ +/* +* Simple driver for Texas Instruments LM3639 Backlight + Flash LED driver chip +* Copyright (C) 2012 Texas Instruments +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +*/ +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/leds.h> +#include <linux/backlight.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/uaccess.h> +#include <linux/interrupt.h> +#include <linux/regmap.h> +#include <linux/platform_data/lm3639_bl.h> + +#define REG_DEV_ID 0x00 +#define REG_CHECKSUM 0x01 +#define REG_BL_CONF_1 0x02 +#define REG_BL_CONF_2 0x03 +#define REG_BL_CONF_3 0x04 +#define REG_BL_CONF_4 0x05 +#define REG_FL_CONF_1 0x06 +#define REG_FL_CONF_2 0x07 +#define REG_FL_CONF_3 0x08 +#define REG_IO_CTRL 0x09 +#define REG_ENABLE 0x0A +#define REG_FLAG 0x0B +#define REG_MAX REG_FLAG + +struct lm3639_chip_data { + struct device *dev; + struct lm3639_platform_data *pdata; + + struct backlight_device *bled; + struct led_classdev cdev_flash; + struct led_classdev cdev_torch; + struct regmap *regmap; + + unsigned int bled_mode; + unsigned int bled_map; + unsigned int last_flag; +}; + +/* initialize chip */ +static int __devinit lm3639_chip_init(struct lm3639_chip_data *pchip) +{ + int ret; + unsigned int reg_val; + struct lm3639_platform_data *pdata = pchip->pdata; + + /* input pins config. */ + ret = + regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x08, + pdata->pin_pwm); + if (ret < 0) + goto out; + + reg_val = (pdata->pin_pwm & 0x40) | pdata->pin_strobe | pdata->pin_tx; + ret = regmap_update_bits(pchip->regmap, REG_IO_CTRL, 0x7C, reg_val); + if (ret < 0) + goto out; + + /* init brightness */ + ret = regmap_write(pchip->regmap, REG_BL_CONF_4, pdata->init_brt_led); + if (ret < 0) + goto out; + + ret = regmap_write(pchip->regmap, REG_BL_CONF_3, pdata->init_brt_led); + if (ret < 0) + goto out; + + /* output pins config. */ + if (!pdata->init_brt_led) + reg_val = pdata->fled_pins | pdata->bled_pins; + else + reg_val = pdata->fled_pins | pdata->bled_pins | 0x01; + + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x79, reg_val); + if (ret < 0) + goto out; + + return ret; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return ret; +} + +/* update and get brightness */ +static int lm3639_bled_update_status(struct backlight_device *bl) +{ + int ret; + unsigned int reg_val; + struct lm3639_chip_data *pchip = bl_get_data(bl); + struct lm3639_platform_data *pdata = pchip->pdata; + + ret = regmap_read(pchip->regmap, REG_FLAG, ®_val); + if (ret < 0) + goto out; + + if (reg_val != 0) + dev_info(pchip->dev, "last flag is 0x%x\n", reg_val); + + /* pwm control */ + if (pdata->pin_pwm) { + if (pdata->pwm_set_intensity) + pdata->pwm_set_intensity(bl->props.brightness, + pdata->max_brt_led); + else + dev_err(pchip->dev, + "No pwm control func. in plat-data\n"); + return bl->props.brightness; + } + + /* i2c control and set brigtness */ + ret = regmap_write(pchip->regmap, REG_BL_CONF_4, bl->props.brightness); + if (ret < 0) + goto out; + ret = regmap_write(pchip->regmap, REG_BL_CONF_3, bl->props.brightness); + if (ret < 0) + goto out; + + if (!bl->props.brightness) + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x01, 0x00); + else + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x01, 0x01); + if (ret < 0) + goto out; + + return bl->props.brightness; +out: + dev_err(pchip->dev, "i2c failed to access registers\n"); + return bl->props.brightness; +} + +static int lm3639_bled_get_brightness(struct backlight_device *bl) +{ + int ret; + unsigned int reg_val; + struct lm3639_chip_data *pchip = bl_get_data(bl); + struct lm3639_platform_data *pdata = pchip->pdata; + + if (pdata->pin_pwm) { + if (pdata->pwm_get_intensity) + bl->props.brightness = pdata->pwm_get_intensity(); + else + dev_err(pchip->dev, + "No pwm control func. in plat-data\n"); + return bl->props.brightness; + } + + ret = regmap_read(pchip->regmap, REG_BL_CONF_1, ®_val); + if (ret < 0) + goto out; + if (reg_val & 0x10) + ret = regmap_read(pchip->regmap, REG_BL_CONF_4, ®_val); + else + ret = regmap_read(pchip->regmap, REG_BL_CONF_3, ®_val); + if (ret < 0) + goto out; + bl->props.brightness = reg_val; + + return bl->props.brightness; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return bl->props.brightness; +} + +static const struct backlight_ops lm3639_bled_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = lm3639_bled_update_status, + .get_brightness = lm3639_bled_get_brightness, +}; + +/* backlight mapping mode */ +static ssize_t lm3639_bled_mode_store(struct device *dev, + struct device_attribute *devAttr, + const char *buf, size_t size) +{ + ssize_t ret; + struct lm3639_chip_data *pchip = dev_get_drvdata(dev); + unsigned int state; + + ret = kstrtouint(buf, 10, &state); + if (ret) + goto out_input; + + if (!state) + ret = + regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x10, + 0x00); + else + ret = + regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x10, + 0x10); + + if (ret < 0) + goto out; + + return size; + +out: + dev_err(pchip->dev, "%s:i2c access fail to register\n", __func__); + return ret; + +out_input: + dev_err(pchip->dev, "%s:input conversion fail\n", __func__); + return ret; + +} + +static DEVICE_ATTR(bled_mode, 0666, NULL, lm3639_bled_mode_store); + +/* torch */ +static void lm3639_torch_brightness_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + int ret; + unsigned int reg_val; + struct lm3639_chip_data *pchip; + + pchip = container_of(cdev, struct lm3639_chip_data, cdev_torch); + + ret = regmap_read(pchip->regmap, REG_FLAG, ®_val); + if (ret < 0) + goto out; + if (reg_val != 0) + dev_info(pchip->dev, "last flag is 0x%x\n", reg_val); + + /* brightness 0 means off state */ + if (!brightness) { + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x00); + if (ret < 0) + goto out; + return; + } + + ret = regmap_update_bits(pchip->regmap, + REG_FL_CONF_1, 0x70, (brightness - 1) << 4); + if (ret < 0) + goto out; + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x02); + if (ret < 0) + goto out; + + return; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return; +} + +/* flash */ +static void lm3639_flash_brightness_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + int ret; + unsigned int reg_val; + struct lm3639_chip_data *pchip; + + pchip = container_of(cdev, struct lm3639_chip_data, cdev_flash); + + ret = regmap_read(pchip->regmap, REG_FLAG, ®_val); + if (ret < 0) + goto out; + if (reg_val != 0) + dev_info(pchip->dev, "last flag is 0x%x\n", reg_val); + + /* torch off before flash control */ + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x00); + if (ret < 0) + goto out; + + /* brightness 0 means off state */ + if (!brightness) + return; + + ret = regmap_update_bits(pchip->regmap, + REG_FL_CONF_1, 0x0F, brightness - 1); + if (ret < 0) + goto out; + ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x06); + if (ret < 0) + goto out; + + return; +out: + dev_err(pchip->dev, "i2c failed to access register\n"); + return; +} + +static const struct regmap_config lm3639_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = REG_MAX, +}; + +static int __devinit lm3639_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct lm3639_chip_data *pchip; + struct lm3639_platform_data *pdata = client->dev.platform_data; + struct backlight_properties props; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "i2c functionality check fail.\n"); + return -EOPNOTSUPP; + } + + if (pdata == NULL) { + dev_err(&client->dev, "Needs Platform Data.\n"); + return -ENODATA; + } + + pchip = devm_kzalloc(&client->dev, + sizeof(struct lm3639_chip_data), GFP_KERNEL); + if (!pchip) + return -ENOMEM; + + pchip->pdata = pdata; + pchip->dev = &client->dev; + + pchip->regmap = devm_regmap_init_i2c(client, &lm3639_regmap); + if (IS_ERR(pchip->regmap)) { + ret = PTR_ERR(pchip->regmap); + dev_err(&client->dev, "fail : allocate register map: %d\n", + ret); + return ret; + } + i2c_set_clientdata(client, pchip); + + /* chip initialize */ + ret = lm3639_chip_init(pchip); + if (ret < 0) { + dev_err(&client->dev, "fail : chip init\n"); + goto err_out; + } + + /* backlight */ + props.type = BACKLIGHT_RAW; + props.brightness = pdata->init_brt_led; + props.max_brightness = pdata->max_brt_led; + pchip->bled = + backlight_device_register("lm3639_bled", pchip->dev, pchip, + &lm3639_bled_ops, &props); + if (IS_ERR(pchip->bled)) { + dev_err(&client->dev, "fail : backlight register\n"); + ret = -EIO; + goto err_out; + } + + ret = device_create_file(&(pchip->bled->dev), &dev_attr_bled_mode); + if (ret < 0) { + dev_err(&client->dev, "failed : add sysfs entries\n"); + ret = -EIO; + goto err_bled_mode; + } + + /* flash */ + pchip->cdev_flash.name = "lm3639_flash"; + pchip->cdev_flash.max_brightness = 16; + pchip->cdev_flash.brightness_set = lm3639_flash_brightness_set; + ret = led_classdev_register((struct device *) + &client->dev, &pchip->cdev_flash); + if (ret < 0) { + dev_err(&client->dev, "fail : flash register\n"); + ret = -EIO; + goto err_flash; + } + + /* torch */ + pchip->cdev_torch.name = "lm3639_torch"; + pchip->cdev_torch.max_brightness = 8; + pchip->cdev_torch.brightness_set = lm3639_torch_brightness_set; + ret = led_classdev_register((struct device *) + &client->dev, &pchip->cdev_torch); + if (ret < 0) { + dev_err(&client->dev, "fail : torch register\n"); + ret = -EIO; + goto err_torch; + } + + return 0; + +err_torch: + led_classdev_unregister(&pchip->cdev_flash); +err_flash: + device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode); +err_bled_mode: + backlight_device_unregister(pchip->bled); +err_out: + return ret; +} + +static int __devexit lm3639_remove(struct i2c_client *client) +{ + struct lm3639_chip_data *pchip = i2c_get_clientdata(client); + + regmap_write(pchip->regmap, REG_ENABLE, 0x00); + + if (&pchip->cdev_torch) + led_classdev_unregister(&pchip->cdev_torch); + if (&pchip->cdev_flash) + led_classdev_unregister(&pchip->cdev_flash); + if (pchip->bled) { + device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode); + backlight_device_unregister(pchip->bled); + } + return 0; +} + +static const struct i2c_device_id lm3639_id[] = { + {LM3639_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, lm3639_id); +static struct i2c_driver lm3639_i2c_driver = { + .driver = { + .name = LM3639_NAME, + }, + .probe = lm3639_probe, + .remove = __devexit_p(lm3639_remove), + .id_table = lm3639_id, +}; + +module_i2c_driver(lm3639_i2c_driver); + +MODULE_DESCRIPTION("Texas Instruments Backlight+Flash LED driver for LM3639"); +MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>"); +MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c index 6c0f1ac0d32a..4066a5bbd826 100644 --- a/drivers/video/backlight/ltv350qv.c +++ b/drivers/video/backlight/ltv350qv.c @@ -75,7 +75,7 @@ static int ltv350qv_power_on(struct ltv350qv *lcd) /* Power On Reset Display off State */ if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, 0x0000)) goto err; - msleep(15); + usleep_range(15000, 16000); /* Power Setting Function 1 */ if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE)) @@ -153,7 +153,7 @@ err_settings: err_power2: err_power1: ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000); - msleep(1); + usleep_range(1000, 1100); err: ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE); return -EIO; @@ -175,7 +175,7 @@ static int ltv350qv_power_off(struct ltv350qv *lcd) ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000); /* Wait at least 1 ms */ - msleep(1); + usleep_range(1000, 1100); /* Power down setting 2 */ ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE); diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index e833ac72e063..f72ba54f364e 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -27,7 +27,9 @@ struct max8925_backlight_data { struct max8925_chip *chip; - int current_brightness; + int current_brightness; + int reg_mode_cntl; + int reg_cntl; }; static int max8925_backlight_set(struct backlight_device *bl, int brightness) @@ -42,16 +44,16 @@ static int max8925_backlight_set(struct backlight_device *bl, int brightness) else value = brightness; - ret = max8925_reg_write(chip->i2c, MAX8925_WLED_CNTL, value); + ret = max8925_reg_write(chip->i2c, data->reg_cntl, value); if (ret < 0) goto out; if (!data->current_brightness && brightness) /* enable WLED output */ - ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 1, 1); + ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 1, 1); else if (!brightness) /* disable WLED output */ - ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 1, 0); + ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 1, 0); if (ret < 0) goto out; dev_dbg(chip->dev, "set brightness %d\n", value); @@ -85,7 +87,7 @@ static int max8925_backlight_get_brightness(struct backlight_device *bl) struct max8925_chip *chip = data->chip; int ret; - ret = max8925_reg_read(chip->i2c, MAX8925_WLED_CNTL); + ret = max8925_reg_read(chip->i2c, data->reg_cntl); if (ret < 0) return -EINVAL; data->current_brightness = ret; @@ -102,69 +104,70 @@ static const struct backlight_ops max8925_backlight_ops = { static int __devinit max8925_backlight_probe(struct platform_device *pdev) { struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct max8925_platform_data *max8925_pdata; - struct max8925_backlight_pdata *pdata = NULL; + struct max8925_backlight_pdata *pdata = pdev->dev.platform_data; struct max8925_backlight_data *data; struct backlight_device *bl; struct backlight_properties props; struct resource *res; - char name[MAX8925_NAME_SIZE]; unsigned char value; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource!\n"); - return -EINVAL; - } - - if (pdev->dev.parent->platform_data) { - max8925_pdata = pdev->dev.parent->platform_data; - pdata = max8925_pdata->backlight; - } - - if (!pdata) { - dev_err(&pdev->dev, "platform data isn't assigned to " - "backlight\n"); - return -EINVAL; - } + int ret = 0; data = devm_kzalloc(&pdev->dev, sizeof(struct max8925_backlight_data), GFP_KERNEL); if (data == NULL) return -ENOMEM; - strncpy(name, res->name, MAX8925_NAME_SIZE); + + res = platform_get_resource(pdev, IORESOURCE_REG, 0); + if (!res) { + dev_err(&pdev->dev, "No REG resource for mode control!\n"); + ret = -ENXIO; + goto out; + } + data->reg_mode_cntl = res->start; + res = platform_get_resource(pdev, IORESOURCE_REG, 1); + if (!res) { + dev_err(&pdev->dev, "No REG resource for control!\n"); + ret = -ENXIO; + goto out; + } + data->reg_cntl = res->start; + data->chip = chip; data->current_brightness = 0; memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = MAX_BRIGHTNESS; - bl = backlight_device_register(name, &pdev->dev, data, + bl = backlight_device_register("max8925-backlight", &pdev->dev, data, &max8925_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); - return PTR_ERR(bl); + ret = PTR_ERR(bl); + goto out; } bl->props.brightness = MAX_BRIGHTNESS; platform_set_drvdata(pdev, bl); value = 0; - if (pdata->lxw_scl) - value |= (1 << 7); - if (pdata->lxw_freq) - value |= (LWX_FREQ(pdata->lxw_freq) << 4); - if (pdata->dual_string) - value |= (1 << 1); - ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 0xfe, value); + if (pdata) { + if (pdata->lxw_scl) + value |= (1 << 7); + if (pdata->lxw_freq) + value |= (LWX_FREQ(pdata->lxw_freq) << 4); + if (pdata->dual_string) + value |= (1 << 1); + } + ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 0xfe, value); if (ret < 0) - goto out; + goto out_brt; backlight_update_status(bl); return 0; -out: +out_brt: backlight_device_unregister(bl); +out: + devm_kfree(&pdev->dev, data); return ret; } diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c index b6672340d6c7..ca4f5d70fe10 100644 --- a/drivers/video/backlight/platform_lcd.c +++ b/drivers/video/backlight/platform_lcd.c @@ -16,6 +16,7 @@ #include <linux/fb.h> #include <linux/backlight.h> #include <linux/lcd.h> +#include <linux/of.h> #include <linux/slab.h> #include <video/platform_lcd.h> @@ -145,6 +146,14 @@ static SIMPLE_DEV_PM_OPS(platform_lcd_pm_ops, platform_lcd_suspend, platform_lcd_resume); #endif +#ifdef CONFIG_OF +static const struct of_device_id platform_lcd_of_match[] = { + { .compatible = "platform-lcd" }, + {}, +}; +MODULE_DEVICE_TABLE(of, platform_lcd_of_match); +#endif + static struct platform_driver platform_lcd_driver = { .driver = { .name = "platform-lcd", @@ -152,6 +161,7 @@ static struct platform_driver platform_lcd_driver = { #ifdef CONFIG_PM .pm = &platform_lcd_pm_ops, #endif + .of_match_table = of_match_ptr(platform_lcd_of_match), }, .probe = platform_lcd_probe, .remove = __devexit_p(platform_lcd_remove), diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c deleted file mode 100644 index 69b35f02929e..000000000000 --- a/drivers/video/backlight/progear_bl.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Backlight Driver for Frontpath ProGear HX1050+ - * - * Copyright (c) 2006 Marcin Juszkiewicz - * - * Based on Progear LCD driver by M Schacht - * <mschacht at alumni dot washington dot edu> - * - * Based on Sharp's Corgi Backlight Driver - * Based on Backlight Driver for HP Jornada 680 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/mutex.h> -#include <linux/fb.h> -#include <linux/backlight.h> -#include <linux/pci.h> - -#define PMU_LPCR 0xB0 -#define SB_MPS1 0x61 -#define HW_LEVEL_MAX 0x77 -#define HW_LEVEL_MIN 0x4f - -static struct pci_dev *pmu_dev = NULL; -static struct pci_dev *sb_dev = NULL; - -static int progearbl_set_intensity(struct backlight_device *bd) -{ - int intensity = bd->props.brightness; - - if (bd->props.power != FB_BLANK_UNBLANK) - intensity = 0; - if (bd->props.fb_blank != FB_BLANK_UNBLANK) - intensity = 0; - - pci_write_config_byte(pmu_dev, PMU_LPCR, intensity + HW_LEVEL_MIN); - - return 0; -} - -static int progearbl_get_intensity(struct backlight_device *bd) -{ - u8 intensity; - pci_read_config_byte(pmu_dev, PMU_LPCR, &intensity); - - return intensity - HW_LEVEL_MIN; -} - -static const struct backlight_ops progearbl_ops = { - .get_brightness = progearbl_get_intensity, - .update_status = progearbl_set_intensity, -}; - -static int progearbl_probe(struct platform_device *pdev) -{ - struct backlight_properties props; - u8 temp; - struct backlight_device *progear_backlight_device; - int ret; - - pmu_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, NULL); - if (!pmu_dev) { - pr_err("ALI M7101 PMU not found.\n"); - return -ENODEV; - } - - sb_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); - if (!sb_dev) { - pr_err("ALI 1533 SB not found.\n"); - ret = -ENODEV; - goto put_pmu; - } - - /* Set SB_MPS1 to enable brightness control. */ - pci_read_config_byte(sb_dev, SB_MPS1, &temp); - pci_write_config_byte(sb_dev, SB_MPS1, temp | 0x20); - - memset(&props, 0, sizeof(struct backlight_properties)); - props.type = BACKLIGHT_RAW; - props.max_brightness = HW_LEVEL_MAX - HW_LEVEL_MIN; - progear_backlight_device = backlight_device_register("progear-bl", - &pdev->dev, NULL, - &progearbl_ops, - &props); - if (IS_ERR(progear_backlight_device)) { - ret = PTR_ERR(progear_backlight_device); - goto put_sb; - } - - platform_set_drvdata(pdev, progear_backlight_device); - - progear_backlight_device->props.power = FB_BLANK_UNBLANK; - progear_backlight_device->props.brightness = HW_LEVEL_MAX - HW_LEVEL_MIN; - progearbl_set_intensity(progear_backlight_device); - - return 0; -put_sb: - pci_dev_put(sb_dev); -put_pmu: - pci_dev_put(pmu_dev); - return ret; -} - -static int progearbl_remove(struct platform_device *pdev) -{ - struct backlight_device *bd = platform_get_drvdata(pdev); - backlight_device_unregister(bd); - - return 0; -} - -static struct platform_driver progearbl_driver = { - .probe = progearbl_probe, - .remove = progearbl_remove, - .driver = { - .name = "progear-bl", - }, -}; - -static struct platform_device *progearbl_device; - -static int __init progearbl_init(void) -{ - int ret = platform_driver_register(&progearbl_driver); - - if (ret) - return ret; - progearbl_device = platform_device_register_simple("progear-bl", -1, - NULL, 0); - if (IS_ERR(progearbl_device)) { - platform_driver_unregister(&progearbl_driver); - return PTR_ERR(progearbl_device); - } - - return 0; -} - -static void __exit progearbl_exit(void) -{ - pci_dev_put(pmu_dev); - pci_dev_put(sb_dev); - - platform_device_unregister(progearbl_device); - platform_driver_unregister(&progearbl_driver); -} - -module_init(progearbl_init); -module_exit(progearbl_exit); - -MODULE_AUTHOR("Marcin Juszkiewicz <linux@hrw.one.pl>"); -MODULE_DESCRIPTION("ProGear Backlight Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 995f0164c9b0..069983ca49ff 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -213,7 +213,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) pb->exit = data->exit; pb->dev = &pdev->dev; - pb->pwm = pwm_get(&pdev->dev, NULL); + pb->pwm = devm_pwm_get(&pdev->dev, NULL); if (IS_ERR(pb->pwm)) { dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n"); @@ -246,7 +246,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); ret = PTR_ERR(bl); - goto err_bl; + goto err_alloc; } bl->props.brightness = data->dft_brightness; @@ -255,8 +255,6 @@ static int pwm_backlight_probe(struct platform_device *pdev) platform_set_drvdata(pdev, bl); return 0; -err_bl: - pwm_put(pb->pwm); err_alloc: if (data->exit) data->exit(&pdev->dev); @@ -271,7 +269,6 @@ static int pwm_backlight_remove(struct platform_device *pdev) backlight_device_unregister(bl); pwm_config(pb->pwm, 0, pb->period); pwm_disable(pb->pwm); - pwm_put(pb->pwm); if (pb->exit) pb->exit(&pdev->dev); return 0; diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c new file mode 100644 index 000000000000..70881633b45a --- /dev/null +++ b/drivers/video/backlight/tps65217_bl.c @@ -0,0 +1,342 @@ +/* + * tps65217_bl.c + * + * TPS65217 backlight driver + * + * Copyright (C) 2012 Matthias Kaehlcke + * Author: Matthias Kaehlcke <matthias@kaehlcke.net> + * + * 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 Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/backlight.h> +#include <linux/err.h> +#include <linux/fb.h> +#include <linux/mfd/tps65217.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +struct tps65217_bl { + struct tps65217 *tps; + struct device *dev; + struct backlight_device *bl; + bool is_enabled; +}; + +static int tps65217_bl_enable(struct tps65217_bl *tps65217_bl) +{ + int rc; + + rc = tps65217_set_bits(tps65217_bl->tps, TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_ISINK_ENABLE, + TPS65217_WLEDCTRL1_ISINK_ENABLE, TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to enable backlight: %d\n", rc); + return rc; + } + + tps65217_bl->is_enabled = true; + + dev_dbg(tps65217_bl->dev, "backlight enabled\n"); + + return 0; +} + +static int tps65217_bl_disable(struct tps65217_bl *tps65217_bl) +{ + int rc; + + rc = tps65217_clear_bits(tps65217_bl->tps, + TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_ISINK_ENABLE, + TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to disable backlight: %d\n", rc); + return rc; + } + + tps65217_bl->is_enabled = false; + + dev_dbg(tps65217_bl->dev, "backlight disabled\n"); + + return 0; +} + +static int tps65217_bl_update_status(struct backlight_device *bl) +{ + struct tps65217_bl *tps65217_bl = bl_get_data(bl); + int rc; + int brightness = bl->props.brightness; + + if (bl->props.state & BL_CORE_SUSPENDED) + brightness = 0; + + if ((bl->props.power != FB_BLANK_UNBLANK) || + (bl->props.fb_blank != FB_BLANK_UNBLANK)) + /* framebuffer in low power mode or blanking active */ + brightness = 0; + + if (brightness > 0) { + rc = tps65217_reg_write(tps65217_bl->tps, + TPS65217_REG_WLEDCTRL2, + brightness - 1, + TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to set brightness level: %d\n", rc); + return rc; + } + + dev_dbg(tps65217_bl->dev, "brightness set to %d\n", brightness); + + if (!tps65217_bl->is_enabled) + rc = tps65217_bl_enable(tps65217_bl); + } else { + rc = tps65217_bl_disable(tps65217_bl); + } + + return rc; +} + +static int tps65217_bl_get_brightness(struct backlight_device *bl) +{ + return bl->props.brightness; +} + +static const struct backlight_ops tps65217_bl_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = tps65217_bl_update_status, + .get_brightness = tps65217_bl_get_brightness +}; + +static int tps65217_bl_hw_init(struct tps65217_bl *tps65217_bl, + struct tps65217_bl_pdata *pdata) +{ + int rc; + + rc = tps65217_bl_disable(tps65217_bl); + if (rc) + return rc; + + switch (pdata->isel) { + case TPS65217_BL_ISET1: + /* select ISET_1 current level */ + rc = tps65217_clear_bits(tps65217_bl->tps, + TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_ISEL, + TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to select ISET1 current level: %d)\n", + rc); + return rc; + } + + dev_dbg(tps65217_bl->dev, "selected ISET1 current level\n"); + + break; + + case TPS65217_BL_ISET2: + /* select ISET2 current level */ + rc = tps65217_set_bits(tps65217_bl->tps, TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_ISEL, + TPS65217_WLEDCTRL1_ISEL, TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to select ISET2 current level: %d\n", + rc); + return rc; + } + + dev_dbg(tps65217_bl->dev, "selected ISET2 current level\n"); + + break; + + default: + dev_err(tps65217_bl->dev, + "invalid value for current level: %d\n", pdata->isel); + return -EINVAL; + } + + /* set PWM frequency */ + rc = tps65217_set_bits(tps65217_bl->tps, + TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_FDIM_MASK, + pdata->fdim, + TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to select PWM dimming frequency: %d\n", + rc); + return rc; + } + + return 0; +} + +#ifdef CONFIG_OF +static struct tps65217_bl_pdata * +tps65217_bl_parse_dt(struct platform_device *pdev) +{ + struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); + struct device_node *node = of_node_get(tps->dev->of_node); + struct tps65217_bl_pdata *pdata, *err; + u32 val; + + node = of_find_node_by_name(node, "backlight"); + if (!node) + return ERR_PTR(-ENODEV); + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, "failed to allocate platform data\n"); + err = ERR_PTR(-ENOMEM); + goto err; + } + + pdata->isel = TPS65217_BL_ISET1; + if (!of_property_read_u32(node, "isel", &val)) { + if (val < TPS65217_BL_ISET1 || + val > TPS65217_BL_ISET2) { + dev_err(&pdev->dev, + "invalid 'isel' value in the device tree\n"); + err = ERR_PTR(-EINVAL); + goto err; + } + + pdata->isel = val; + } + + pdata->fdim = TPS65217_BL_FDIM_200HZ; + if (!of_property_read_u32(node, "fdim", &val)) { + switch (val) { + case 100: + pdata->fdim = TPS65217_BL_FDIM_100HZ; + break; + + case 200: + pdata->fdim = TPS65217_BL_FDIM_200HZ; + break; + + case 500: + pdata->fdim = TPS65217_BL_FDIM_500HZ; + break; + + case 1000: + pdata->fdim = TPS65217_BL_FDIM_1000HZ; + break; + + default: + dev_err(&pdev->dev, + "invalid 'fdim' value in the device tree\n"); + err = ERR_PTR(-EINVAL); + goto err; + } + } + + of_node_put(node); + + return pdata; + +err: + of_node_put(node); + + return err; +} +#else +static struct tps65217_bl_pdata * +tps65217_bl_parse_dt(struct platform_device *pdev) +{ + return NULL; +} +#endif + +static int tps65217_bl_probe(struct platform_device *pdev) +{ + int rc; + struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); + struct tps65217_bl *tps65217_bl; + struct tps65217_bl_pdata *pdata; + struct backlight_properties bl_props; + + if (tps->dev->of_node) { + pdata = tps65217_bl_parse_dt(pdev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + } else { + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "no platform data provided\n"); + return -EINVAL; + } + + pdata = pdev->dev.platform_data; + } + + tps65217_bl = devm_kzalloc(&pdev->dev, sizeof(*tps65217_bl), + GFP_KERNEL); + if (tps65217_bl == NULL) { + dev_err(&pdev->dev, "allocation of struct tps65217_bl failed\n"); + return -ENOMEM; + } + + tps65217_bl->tps = tps; + tps65217_bl->dev = &pdev->dev; + tps65217_bl->is_enabled = false; + + rc = tps65217_bl_hw_init(tps65217_bl, pdata); + if (rc) + return rc; + + memset(&bl_props, 0, sizeof(struct backlight_properties)); + bl_props.type = BACKLIGHT_RAW; + bl_props.max_brightness = 100; + + tps65217_bl->bl = backlight_device_register(pdev->name, + tps65217_bl->dev, tps65217_bl, + &tps65217_bl_ops, &bl_props); + if (IS_ERR(tps65217_bl->bl)) { + dev_err(tps65217_bl->dev, + "registration of backlight device failed: %d\n", rc); + return PTR_ERR(tps65217_bl->bl); + } + + tps65217_bl->bl->props.brightness = 0; + platform_set_drvdata(pdev, tps65217_bl); + + return 0; +} + +static int tps65217_bl_remove(struct platform_device *pdev) +{ + struct tps65217_bl *tps65217_bl = platform_get_drvdata(pdev); + + backlight_device_unregister(tps65217_bl->bl); + + return 0; +} + +static struct platform_driver tps65217_bl_driver = { + .probe = tps65217_bl_probe, + .remove = tps65217_bl_remove, + .driver = { + .owner = THIS_MODULE, + .name = "tps65217-bl", + }, +}; + +module_platform_driver(tps65217_bl_driver); + +MODULE_DESCRIPTION("TPS65217 Backlight driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Matthias Kaehlcke <matthias@kaehlcke.net>"); diff --git a/drivers/video/bf537-lq035.c b/drivers/video/bf537-lq035.c index befbc80d11fc..7347aa1e5e4a 100644 --- a/drivers/video/bf537-lq035.c +++ b/drivers/video/bf537-lq035.c @@ -760,18 +760,20 @@ static int __devinit bfin_lq035_probe(struct platform_device *pdev) bfin_lq035_fb.flags = FBINFO_DEFAULT; - bfin_lq035_fb.pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL); + bfin_lq035_fb.pseudo_palette = devm_kzalloc(&pdev->dev, + sizeof(u32) * 16, + GFP_KERNEL); if (bfin_lq035_fb.pseudo_palette == NULL) { pr_err("failed to allocate pseudo_palette\n"); ret = -ENOMEM; - goto out_palette; + goto out_table; } if (fb_alloc_cmap(&bfin_lq035_fb.cmap, NBR_PALETTE, 0) < 0) { pr_err("failed to allocate colormap (%d entries)\n", NBR_PALETTE); ret = -EFAULT; - goto out_cmap; + goto out_table; } if (register_framebuffer(&bfin_lq035_fb) < 0) { @@ -804,9 +806,6 @@ out_lcd: unregister_framebuffer(&bfin_lq035_fb); out_reg: fb_dealloc_cmap(&bfin_lq035_fb.cmap); -out_cmap: - kfree(bfin_lq035_fb.pseudo_palette); -out_palette: out_table: dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0); fb_buffer = NULL; @@ -834,7 +833,6 @@ static int __devexit bfin_lq035_remove(struct platform_device *pdev) free_dma(CH_PPI); - kfree(bfin_lq035_fb.pseudo_palette); fb_dealloc_cmap(&bfin_lq035_fb.cmap); diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index dc2f0047769b..ff5663f5c64f 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -525,6 +525,7 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev) info = fbinfo->par; info->fb = fbinfo; info->dev = &pdev->dev; + spin_lock_init(&info->lock); platform_set_drvdata(pdev, fbinfo); @@ -601,7 +602,8 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev) fbinfo->fbops = &bfin_bf54x_fb_ops; - fbinfo->pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL); + fbinfo->pseudo_palette = devm_kzalloc(&pdev->dev, sizeof(u32) * 16, + GFP_KERNEL); if (!fbinfo->pseudo_palette) { printk(KERN_ERR DRIVER_NAME "Fail to allocate pseudo_palette\n"); @@ -616,7 +618,7 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev) "Fail to allocate colormap (%d entries)\n", BFIN_LCD_NBR_PALETTE_ENTRIES); ret = -EFAULT; - goto out5; + goto out4; } if (request_ports(info)) { @@ -671,8 +673,6 @@ out7: free_ports(info); out6: fb_dealloc_cmap(&fbinfo->cmap); -out5: - kfree(fbinfo->pseudo_palette); out4: dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, info->dma_handle); @@ -699,7 +699,6 @@ static int __devexit bfin_bf54x_remove(struct platform_device *pdev) dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, info->dma_handle); - kfree(fbinfo->pseudo_palette); fb_dealloc_cmap(&fbinfo->cmap); #ifndef NO_BL_SUPPORT diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c index 353c02fe8a95..6fbc75c2f0a1 100644 --- a/drivers/video/bfin-lq035q1-fb.c +++ b/drivers/video/bfin-lq035q1-fb.c @@ -577,6 +577,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) info = fbinfo->par; info->fb = fbinfo; info->dev = &pdev->dev; + spin_lock_init(&info->lock); info->disp_info = pdev->dev.platform_data; @@ -853,17 +854,7 @@ static struct platform_driver bfin_lq035q1_driver = { }, }; -static int __init bfin_lq035q1_driver_init(void) -{ - return platform_driver_register(&bfin_lq035q1_driver); -} -module_init(bfin_lq035q1_driver_init); - -static void __exit bfin_lq035q1_driver_cleanup(void) -{ - platform_driver_unregister(&bfin_lq035q1_driver); -} -module_exit(bfin_lq035q1_driver_cleanup); +module_platform_driver(bfin_lq035q1_driver); MODULE_DESCRIPTION("Blackfin TFT LCD Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index 7a0c05f3537e..ae0fb24b8b43 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c @@ -447,6 +447,7 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) info = fbinfo->par; info->fb = fbinfo; info->dev = &pdev->dev; + spin_lock_init(&info->lock); platform_set_drvdata(pdev, fbinfo); diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index 7ba74cd4be61..6bea9a936798 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -319,8 +319,10 @@ static int __devinit bw2_probe(struct platform_device *op) info->screen_base = of_ioremap(&op->resource[0], 0, info->fix.smem_len, "bw2 ram"); - if (!info->screen_base) + if (!info->screen_base) { + err = -ENOMEM; goto out_unmap_regs; + } bw2_blank(FB_BLANK_UNBLANK, info); diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index f927a7b1a8d4..c5e7612ff876 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -398,7 +398,8 @@ static int __devinit cg3_probe(struct platform_device *op) goto out_unmap_screen; } - if (fb_alloc_cmap(&info->cmap, 256, 0)) + err = fb_alloc_cmap(&info->cmap, 256, 0); + if (err) goto out_unmap_screen; fb_set_cmap(&info->cmap, info); diff --git a/drivers/video/cobalt_lcdfb.c b/drivers/video/cobalt_lcdfb.c index eae46f6457e2..01a4ee7cc6b1 100644 --- a/drivers/video/cobalt_lcdfb.c +++ b/drivers/video/cobalt_lcdfb.c @@ -348,7 +348,8 @@ static int __devinit cobalt_lcdfb_probe(struct platform_device *dev) } info->screen_size = resource_size(res); - info->screen_base = ioremap(res->start, info->screen_size); + info->screen_base = devm_ioremap(&dev->dev, res->start, + info->screen_size); info->fbops = &cobalt_lcd_fbops; info->fix = cobalt_lcdfb_fix; info->fix.smem_start = res->start; @@ -359,7 +360,6 @@ static int __devinit cobalt_lcdfb_probe(struct platform_device *dev) retval = register_framebuffer(info); if (retval < 0) { - iounmap(info->screen_base); framebuffer_release(info); return retval; } @@ -380,7 +380,6 @@ static int __devexit cobalt_lcdfb_remove(struct platform_device *dev) info = platform_get_drvdata(dev); if (info) { - iounmap(info->screen_base); unregister_framebuffer(info); framebuffer_release(info); } diff --git a/drivers/video/console/font_mini_4x6.c b/drivers/video/console/font_mini_4x6.c index fa6e698e63c4..838caa1cfef7 100644 --- a/drivers/video/console/font_mini_4x6.c +++ b/drivers/video/console/font_mini_4x6.c @@ -1092,7 +1092,7 @@ static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = { /*{*/ /* Char 124: '|' */ 0x44, /*= [ * ] */ 0x44, /*= [ * ] */ - 0x00, /*= [ ] */ + 0x44, /*= [ * ] */ 0x44, /*= [ * ] */ 0x44, /*= [ * ] */ 0x00, /*= [ ] */ diff --git a/drivers/video/console/font_sun8x16.c b/drivers/video/console/font_sun8x16.c index 5abf290c6eb7..268151325b83 100644 --- a/drivers/video/console/font_sun8x16.c +++ b/drivers/video/console/font_sun8x16.c @@ -127,7 +127,7 @@ static const unsigned char fontdata_sun8x16[FONTDATAMAX] = { /*y*/ 0x00,0x00,0x00,0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7e,0x06,0x0c,0xf8,0x00, /*z*/ 0x00,0x00,0x00,0x00,0x00,0xfe,0xcc,0x18,0x30,0x60,0xc6,0xfe,0x00,0x00,0x00,0x00, /*{*/ 0x00,0x00,0x0e,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0e,0x00,0x00,0x00,0x00, -/*|*/ 0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, +/*|*/ 0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, /*}*/ 0x00,0x00,0x70,0x18,0x18,0x18,0x0e,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00, /*~*/ 0x00,0x00,0x76,0xdc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* */ 0x00,0x00,0x00,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xc6,0xfe,0x00,0x00,0x00,0x00,0x00, diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index c1527f5b47ee..e40125cb313e 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c @@ -1804,8 +1804,10 @@ cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) cfb->irq = dev->irq; cfb->region = pci_ioremap_bar(dev, 0); - if (!cfb->region) + if (!cfb->region) { + err = -ENOMEM; goto failed_ioremap; + } cfb->regs = cfb->region + MMIO_OFFSET; cfb->fb.device = &dev->dev; diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 113d43a16f54..80665f66ac1a 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -26,7 +26,9 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/uaccess.h> +#include <linux/pm_runtime.h> #include <linux/interrupt.h> +#include <linux/wait.h> #include <linux/clk.h> #include <linux/cpufreq.h> #include <linux/console.h> @@ -48,6 +50,7 @@ #define LCD_PL_LOAD_DONE BIT(6) #define LCD_FIFO_UNDERFLOW BIT(5) #define LCD_SYNC_LOST BIT(2) +#define LCD_FRAME_DONE BIT(0) /* LCD DMA Control Register */ #define LCD_DMA_BURST_SIZE(x) ((x) << 4) @@ -86,6 +89,8 @@ #define LCD_V2_LIDD_CLK_EN BIT(1) #define LCD_V2_CORE_CLK_EN BIT(0) #define LCD_V2_LPP_B10 26 +#define LCD_V2_TFT_24BPP_MODE BIT(25) +#define LCD_V2_TFT_24BPP_UNPACK BIT(26) /* LCD Raster Timing 2 Register */ #define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16) @@ -135,6 +140,8 @@ static void __iomem *da8xx_fb_reg_base; static struct resource *lcdc_regs; static unsigned int lcd_revision; static irq_handler_t lcdc_irq_handler; +static wait_queue_head_t frame_done_wq; +static int frame_done_flag; static inline unsigned int lcdc_read(unsigned int addr) { @@ -156,7 +163,6 @@ struct da8xx_fb_par { unsigned int dma_end; struct clk *lcdc_clk; int irq; - unsigned short pseudo_palette[16]; unsigned int palette_sz; unsigned int pxl_clk; int blank; @@ -175,6 +181,7 @@ struct da8xx_fb_par { unsigned int lcd_fck_rate; #endif void (*panel_power_ctrl)(int); + u32 pseudo_palette[16]; }; /* Variable Screen Information */ @@ -288,13 +295,26 @@ static inline void lcd_enable_raster(void) } /* Disable the Raster Engine of the LCD Controller */ -static inline void lcd_disable_raster(void) +static inline void lcd_disable_raster(bool wait_for_frame_done) { u32 reg; + int ret; reg = lcdc_read(LCD_RASTER_CTRL_REG); if (reg & LCD_RASTER_ENABLE) lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); + else + /* return if already disabled */ + return; + + if ((wait_for_frame_done == true) && (lcd_revision == LCD_VERSION_2)) { + frame_done_flag = 0; + ret = wait_event_interruptible_timeout(frame_done_wq, + frame_done_flag != 0, + msecs_to_jiffies(50)); + if (ret == 0) + pr_err("LCD Controller timed out\n"); + } } static void lcd_blit(int load_mode, struct da8xx_fb_par *par) @@ -321,7 +341,8 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par) } else { reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) | LCD_V2_END_OF_FRAME0_INT_ENA | - LCD_V2_END_OF_FRAME1_INT_ENA; + LCD_V2_END_OF_FRAME1_INT_ENA | + LCD_FRAME_DONE; lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG); } reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE; @@ -499,6 +520,9 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, { u32 reg; + if (bpp > 16 && lcd_revision == LCD_VERSION_1) + return -EINVAL; + /* Set the Panel Width */ /* Pixels per line = (PPL + 1)*16 */ if (lcd_revision == LCD_VERSION_1) { @@ -542,14 +566,19 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8); if (raster_order) reg |= LCD_RASTER_ORDER; - lcdc_write(reg, LCD_RASTER_CTRL_REG); + + par->palette_sz = 16 * 2; switch (bpp) { case 1: case 2: case 4: case 16: - par->palette_sz = 16 * 2; + break; + case 24: + reg |= LCD_V2_TFT_24BPP_MODE; + case 32: + reg |= LCD_V2_TFT_24BPP_UNPACK; break; case 8: @@ -560,9 +589,12 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, return -EINVAL; } + lcdc_write(reg, LCD_RASTER_CTRL_REG); + return 0; } +#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16) static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) @@ -578,13 +610,38 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) return 1; - if (info->var.bits_per_pixel == 4) { - if (regno > 15) - return 1; + if (info->var.bits_per_pixel > 16 && lcd_revision == LCD_VERSION_1) + return -EINVAL; - if (info->var.grayscale) { - pal = regno; - } else { + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + break; + case FB_VISUAL_PSEUDOCOLOR: + switch (info->var.bits_per_pixel) { + case 4: + if (regno > 15) + return -EINVAL; + + if (info->var.grayscale) { + pal = regno; + } else { + red >>= 4; + green >>= 8; + blue >>= 12; + + pal = red & 0x0f00; + pal |= green & 0x00f0; + pal |= blue & 0x000f; + } + if (regno == 0) + pal |= 0x2000; + palette[regno] = pal; + break; + + case 8: red >>= 4; green >>= 8; blue >>= 12; @@ -592,36 +649,36 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, pal = (red & 0x0f00); pal |= (green & 0x00f0); pal |= (blue & 0x000f); - } - if (regno == 0) - pal |= 0x2000; - palette[regno] = pal; - - } else if (info->var.bits_per_pixel == 8) { - red >>= 4; - green >>= 8; - blue >>= 12; - - pal = (red & 0x0f00); - pal |= (green & 0x00f0); - pal |= (blue & 0x000f); - if (palette[regno] != pal) { - update_hw = 1; - palette[regno] = pal; + if (palette[regno] != pal) { + update_hw = 1; + palette[regno] = pal; + } + break; } - } else if ((info->var.bits_per_pixel == 16) && regno < 16) { - red >>= (16 - info->var.red.length); - red <<= info->var.red.offset; + break; + } - green >>= (16 - info->var.green.length); - green <<= info->var.green.offset; + /* Truecolor has hardware independent palette */ + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + u32 v; - blue >>= (16 - info->var.blue.length); - blue <<= info->var.blue.offset; + if (regno > 15) + return -EINVAL; - par->pseudo_palette[regno] = red | green | blue; + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + switch (info->var.bits_per_pixel) { + case 16: + ((u16 *) (info->pseudo_palette))[regno] = v; + break; + case 24: + case 32: + ((u32 *) (info->pseudo_palette))[regno] = v; + break; + } if (palette[0] != 0x4000) { update_hw = 1; palette[0] = 0x4000; @@ -634,11 +691,12 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, return 0; } +#undef CNVT_TOHW static void lcd_reset(struct da8xx_fb_par *par) { /* Disable the Raster if previously Enabled */ - lcd_disable_raster(); + lcd_disable_raster(false); /* DMA has to be disabled */ lcdc_write(0, LCD_DMA_CTRL_REG); @@ -734,7 +792,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg) u32 stat = lcdc_read(LCD_MASKED_STAT_REG); if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { - lcd_disable_raster(); + lcd_disable_raster(false); lcdc_write(stat, LCD_MASKED_STAT_REG); lcd_enable_raster(); } else if (stat & LCD_PL_LOAD_DONE) { @@ -744,7 +802,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg) * interrupt via the following write to the status register. If * this is done after then one gets multiple PL done interrupts. */ - lcd_disable_raster(); + lcd_disable_raster(false); lcdc_write(stat, LCD_MASKED_STAT_REG); @@ -775,6 +833,14 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg) par->vsync_flag = 1; wake_up_interruptible(&par->vsync_wait); } + + /* Set only when controller is disabled and at the end of + * active frame + */ + if (stat & BIT(0)) { + frame_done_flag = 1; + wake_up_interruptible(&frame_done_wq); + } } lcdc_write(0, LCD_END_OF_INT_IND_REG); @@ -789,7 +855,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg) u32 reg_ras; if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { - lcd_disable_raster(); + lcd_disable_raster(false); lcdc_write(stat, LCD_STAT_REG); lcd_enable_raster(); } else if (stat & LCD_PL_LOAD_DONE) { @@ -799,7 +865,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg) * interrupt via the following write to the status register. If * this is done after then one gets multiple PL done interrupts. */ - lcd_disable_raster(); + lcd_disable_raster(false); lcdc_write(stat, LCD_STAT_REG); @@ -842,6 +908,9 @@ static int fb_check_var(struct fb_var_screeninfo *var, { int err = 0; + if (var->bits_per_pixel > 16 && lcd_revision == LCD_VERSION_1) + return -EINVAL; + switch (var->bits_per_pixel) { case 1: case 8: @@ -877,6 +946,26 @@ static int fb_check_var(struct fb_var_screeninfo *var, var->transp.length = 0; var->nonstd = 0; break; + case 24: + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->nonstd = 0; + break; + case 32: + var->transp.offset = 24; + var->transp.length = 8; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->nonstd = 0; + break; default: err = -EINVAL; } @@ -898,9 +987,10 @@ static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb, if (val == CPUFREQ_POSTCHANGE) { if (par->lcd_fck_rate != clk_get_rate(par->lcdc_clk)) { par->lcd_fck_rate = clk_get_rate(par->lcdc_clk); - lcd_disable_raster(); + lcd_disable_raster(true); lcd_calc_clk_divider(par); - lcd_enable_raster(); + if (par->blank == FB_BLANK_UNBLANK) + lcd_enable_raster(); } } @@ -935,7 +1025,7 @@ static int __devexit fb_remove(struct platform_device *dev) if (par->panel_power_ctrl) par->panel_power_ctrl(0); - lcd_disable_raster(); + lcd_disable_raster(true); lcdc_write(0, LCD_RASTER_CTRL_REG); /* disable DMA */ @@ -948,8 +1038,8 @@ static int __devexit fb_remove(struct platform_device *dev) dma_free_coherent(NULL, par->vram_size, par->vram_virt, par->vram_phys); free_irq(par->irq, par); - clk_disable(par->lcdc_clk); - clk_put(par->lcdc_clk); + pm_runtime_put_sync(&dev->dev); + pm_runtime_disable(&dev->dev); framebuffer_release(info); iounmap(da8xx_fb_reg_base); release_mem_region(lcdc_regs->start, resource_size(lcdc_regs)); @@ -1051,7 +1141,7 @@ static int cfb_blank(int blank, struct fb_info *info) if (par->panel_power_ctrl) par->panel_power_ctrl(0); - lcd_disable_raster(); + lcd_disable_raster(true); break; default: ret = -EINVAL; @@ -1183,9 +1273,9 @@ static int __devinit fb_probe(struct platform_device *device) ret = -ENODEV; goto err_ioremap; } - ret = clk_enable(fb_clk); - if (ret) - goto err_clk_put; + + pm_runtime_enable(&device->dev); + pm_runtime_get_sync(&device->dev); /* Determine LCD IP Version */ switch (lcdc_read(LCD_PID_REG)) { @@ -1213,7 +1303,7 @@ static int __devinit fb_probe(struct platform_device *device) if (i == ARRAY_SIZE(known_lcd_panels)) { dev_err(&device->dev, "GLCD: No valid panel found\n"); ret = -ENODEV; - goto err_clk_disable; + goto err_pm_runtime_disable; } else dev_info(&device->dev, "GLCD: Found %s panel\n", fb_pdata->type); @@ -1225,7 +1315,7 @@ static int __devinit fb_probe(struct platform_device *device) if (!da8xx_fb_info) { dev_dbg(&device->dev, "Memory allocation failed for fb_info\n"); ret = -ENOMEM; - goto err_clk_disable; + goto err_pm_runtime_disable; } par = da8xx_fb_info->par; @@ -1356,8 +1446,10 @@ static int __devinit fb_probe(struct platform_device *device) if (lcd_revision == LCD_VERSION_1) lcdc_irq_handler = lcdc_irq_handler_rev01; - else + else { + init_waitqueue_head(&frame_done_wq); lcdc_irq_handler = lcdc_irq_handler_rev02; + } ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par); @@ -1385,11 +1477,9 @@ err_release_fb_mem: err_release_fb: framebuffer_release(da8xx_fb_info); -err_clk_disable: - clk_disable(fb_clk); - -err_clk_put: - clk_put(fb_clk); +err_pm_runtime_disable: + pm_runtime_put_sync(&device->dev); + pm_runtime_disable(&device->dev); err_ioremap: iounmap(da8xx_fb_reg_base); @@ -1401,6 +1491,69 @@ err_request_mem: } #ifdef CONFIG_PM +struct lcdc_context { + u32 clk_enable; + u32 ctrl; + u32 dma_ctrl; + u32 raster_timing_0; + u32 raster_timing_1; + u32 raster_timing_2; + u32 int_enable_set; + u32 dma_frm_buf_base_addr_0; + u32 dma_frm_buf_ceiling_addr_0; + u32 dma_frm_buf_base_addr_1; + u32 dma_frm_buf_ceiling_addr_1; + u32 raster_ctrl; +} reg_context; + +static void lcd_context_save(void) +{ + if (lcd_revision == LCD_VERSION_2) { + reg_context.clk_enable = lcdc_read(LCD_CLK_ENABLE_REG); + reg_context.int_enable_set = lcdc_read(LCD_INT_ENABLE_SET_REG); + } + + reg_context.ctrl = lcdc_read(LCD_CTRL_REG); + reg_context.dma_ctrl = lcdc_read(LCD_DMA_CTRL_REG); + reg_context.raster_timing_0 = lcdc_read(LCD_RASTER_TIMING_0_REG); + reg_context.raster_timing_1 = lcdc_read(LCD_RASTER_TIMING_1_REG); + reg_context.raster_timing_2 = lcdc_read(LCD_RASTER_TIMING_2_REG); + reg_context.dma_frm_buf_base_addr_0 = + lcdc_read(LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); + reg_context.dma_frm_buf_ceiling_addr_0 = + lcdc_read(LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); + reg_context.dma_frm_buf_base_addr_1 = + lcdc_read(LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); + reg_context.dma_frm_buf_ceiling_addr_1 = + lcdc_read(LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); + reg_context.raster_ctrl = lcdc_read(LCD_RASTER_CTRL_REG); + return; +} + +static void lcd_context_restore(void) +{ + if (lcd_revision == LCD_VERSION_2) { + lcdc_write(reg_context.clk_enable, LCD_CLK_ENABLE_REG); + lcdc_write(reg_context.int_enable_set, LCD_INT_ENABLE_SET_REG); + } + + lcdc_write(reg_context.ctrl, LCD_CTRL_REG); + lcdc_write(reg_context.dma_ctrl, LCD_DMA_CTRL_REG); + lcdc_write(reg_context.raster_timing_0, LCD_RASTER_TIMING_0_REG); + lcdc_write(reg_context.raster_timing_1, LCD_RASTER_TIMING_1_REG); + lcdc_write(reg_context.raster_timing_2, LCD_RASTER_TIMING_2_REG); + lcdc_write(reg_context.dma_frm_buf_base_addr_0, + LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); + lcdc_write(reg_context.dma_frm_buf_ceiling_addr_0, + LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); + lcdc_write(reg_context.dma_frm_buf_base_addr_1, + LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); + lcdc_write(reg_context.dma_frm_buf_ceiling_addr_1, + LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); + lcdc_write(reg_context.raster_ctrl, LCD_RASTER_CTRL_REG); + return; +} + static int fb_suspend(struct platform_device *dev, pm_message_t state) { struct fb_info *info = platform_get_drvdata(dev); @@ -1411,8 +1564,9 @@ static int fb_suspend(struct platform_device *dev, pm_message_t state) par->panel_power_ctrl(0); fb_set_suspend(info, 1); - lcd_disable_raster(); - clk_disable(par->lcdc_clk); + lcd_disable_raster(true); + lcd_context_save(); + pm_runtime_put_sync(&dev->dev); console_unlock(); return 0; @@ -1423,11 +1577,14 @@ static int fb_resume(struct platform_device *dev) struct da8xx_fb_par *par = info->par; console_lock(); - clk_enable(par->lcdc_clk); - lcd_enable_raster(); + pm_runtime_get_sync(&dev->dev); + lcd_context_restore(); + if (par->blank == FB_BLANK_UNBLANK) { + lcd_enable_raster(); - if (par->panel_power_ctrl) - par->panel_power_ctrl(1); + if (par->panel_power_ctrl) + par->panel_power_ctrl(1); + } fb_set_suspend(info, 0); console_unlock(); diff --git a/drivers/video/ep93xx-fb.c b/drivers/video/ep93xx-fb.c index f2c092da84b0..755ef3e65caf 100644 --- a/drivers/video/ep93xx-fb.c +++ b/drivers/video/ep93xx-fb.c @@ -529,7 +529,8 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev) * any of the framebuffer registers. */ fbi->res = res; - fbi->mmio_base = ioremap(res->start, resource_size(res)); + fbi->mmio_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); if (!fbi->mmio_base) { err = -ENXIO; goto failed_resource; @@ -553,20 +554,20 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev) if (err == 0) { dev_err(info->dev, "No suitable video mode found\n"); err = -EINVAL; - goto failed_mode; + goto failed_resource; } if (mach_info->setup) { err = mach_info->setup(pdev); if (err) - goto failed_mode; + goto failed_resource; } err = ep93xxfb_check_var(&info->var, info); if (err) goto failed_check; - fbi->clk = clk_get(info->dev, NULL); + fbi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(fbi->clk)) { err = PTR_ERR(fbi->clk); fbi->clk = NULL; @@ -578,19 +579,15 @@ static int __devinit ep93xxfb_probe(struct platform_device *pdev) err = register_framebuffer(info); if (err) - goto failed; + goto failed_check; dev_info(info->dev, "registered. Mode = %dx%d-%d\n", info->var.xres, info->var.yres, info->var.bits_per_pixel); return 0; -failed: - clk_put(fbi->clk); failed_check: if (fbi->mach_info->teardown) fbi->mach_info->teardown(pdev); -failed_mode: - iounmap(fbi->mmio_base); failed_resource: ep93xxfb_dealloc_videomem(info); failed_videomem: @@ -609,8 +606,6 @@ static int __devexit ep93xxfb_remove(struct platform_device *pdev) unregister_framebuffer(info); clk_disable(fbi->clk); - clk_put(fbi->clk); - iounmap(fbi->mmio_base); ep93xxfb_dealloc_videomem(info); fb_dealloc_cmap(&info->cmap); diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c index c6c016a506ce..d55470e75412 100644 --- a/drivers/video/exynos/exynos_dp_core.c +++ b/drivers/video/exynos/exynos_dp_core.c @@ -29,6 +29,9 @@ static int exynos_dp_init_dp(struct exynos_dp_device *dp) exynos_dp_swreset(dp); + exynos_dp_init_analog_param(dp); + exynos_dp_init_interrupt(dp); + /* SW defined function Normal operation */ exynos_dp_enable_sw_function(dp); @@ -260,7 +263,7 @@ static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp, static void exynos_dp_link_start(struct exynos_dp_device *dp) { - u8 buf[5]; + u8 buf[4]; int lane; int lane_count; @@ -295,10 +298,10 @@ static void exynos_dp_link_start(struct exynos_dp_device *dp) exynos_dp_set_training_pattern(dp, TRAINING_PTN1); /* Set RX training pattern */ - buf[0] = DPCD_SCRAMBLING_DISABLED | - DPCD_TRAINING_PATTERN_1; exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, buf[0]); + DPCD_ADDR_TRAINING_PATTERN_SET, + DPCD_SCRAMBLING_DISABLED | + DPCD_TRAINING_PATTERN_1); for (lane = 0; lane < lane_count; lane++) buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 | @@ -308,7 +311,7 @@ static void exynos_dp_link_start(struct exynos_dp_device *dp) lane_count, buf); } -static unsigned char exynos_dp_get_lane_status(u8 link_status[6], int lane) +static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane) { int shift = (lane & 1) * 4; u8 link_value = link_status[lane>>1]; @@ -316,7 +319,7 @@ static unsigned char exynos_dp_get_lane_status(u8 link_status[6], int lane) return (link_value >> shift) & 0xf; } -static int exynos_dp_clock_recovery_ok(u8 link_status[6], int lane_count) +static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count) { int lane; u8 lane_status; @@ -329,22 +332,23 @@ static int exynos_dp_clock_recovery_ok(u8 link_status[6], int lane_count) return 0; } -static int exynos_dp_channel_eq_ok(u8 link_status[6], int lane_count) +static int exynos_dp_channel_eq_ok(u8 link_align[3], int lane_count) { int lane; u8 lane_align; u8 lane_status; - lane_align = link_status[2]; + lane_align = link_align[2]; if ((lane_align & DPCD_INTERLANE_ALIGN_DONE) == 0) return -EINVAL; for (lane = 0; lane < lane_count; lane++) { - lane_status = exynos_dp_get_lane_status(link_status, lane); + lane_status = exynos_dp_get_lane_status(link_align, lane); lane_status &= DPCD_CHANNEL_EQ_BITS; if (lane_status != DPCD_CHANNEL_EQ_BITS) return -EINVAL; } + return 0; } @@ -417,69 +421,17 @@ static unsigned int exynos_dp_get_lane_link_training( static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp) { - if (dp->link_train.link_rate == LINK_RATE_2_70GBPS) { - /* set to reduced bit rate */ - dp->link_train.link_rate = LINK_RATE_1_62GBPS; - dev_err(dp->dev, "set to bandwidth %.2x\n", - dp->link_train.link_rate); - dp->link_train.lt_state = START; - } else { - exynos_dp_training_pattern_dis(dp); - /* set enhanced mode if available */ - exynos_dp_set_enhanced_mode(dp); - dp->link_train.lt_state = FAILED; - } -} + exynos_dp_training_pattern_dis(dp); + exynos_dp_set_enhanced_mode(dp); -static void exynos_dp_get_adjust_train(struct exynos_dp_device *dp, - u8 adjust_request[2]) -{ - int lane; - int lane_count; - u8 voltage_swing; - u8 pre_emphasis; - u8 training_lane; - - lane_count = dp->link_train.lane_count; - for (lane = 0; lane < lane_count; lane++) { - voltage_swing = exynos_dp_get_adjust_request_voltage( - adjust_request, lane); - pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( - adjust_request, lane); - training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | - DPCD_PRE_EMPHASIS_SET(pre_emphasis); - - if (voltage_swing == VOLTAGE_LEVEL_3 || - pre_emphasis == PRE_EMPHASIS_LEVEL_3) { - training_lane |= DPCD_MAX_SWING_REACHED; - training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; - } - dp->link_train.training_lane[lane] = training_lane; - } -} - -static int exynos_dp_check_max_cr_loop(struct exynos_dp_device *dp, - u8 voltage_swing) -{ - int lane; - int lane_count; - - lane_count = dp->link_train.lane_count; - for (lane = 0; lane < lane_count; lane++) { - if (voltage_swing == VOLTAGE_LEVEL_3 || - dp->link_train.cr_loop[lane] == MAX_CR_LOOP) - return -EINVAL; - } - return 0; + dp->link_train.lt_state = FAILED; } static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) { - u8 data; - u8 link_status[6]; + u8 link_status[2]; int lane; int lane_count; - u8 buf[5]; u8 adjust_request[2]; u8 voltage_swing; @@ -488,100 +440,154 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) usleep_range(100, 101); - exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, - 6, link_status); lane_count = dp->link_train.lane_count; + exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, + 2, link_status); + if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { /* set training pattern 2 for EQ */ exynos_dp_set_training_pattern(dp, TRAINING_PTN2); - adjust_request[0] = link_status[4]; - adjust_request[1] = link_status[5]; + for (lane = 0; lane < lane_count; lane++) { + exynos_dp_read_bytes_from_dpcd(dp, + DPCD_ADDR_ADJUST_REQUEST_LANE0_1, + 2, adjust_request); + voltage_swing = exynos_dp_get_adjust_request_voltage( + adjust_request, lane); + pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( + adjust_request, lane); + training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | + DPCD_PRE_EMPHASIS_SET(pre_emphasis); - exynos_dp_get_adjust_train(dp, adjust_request); + if (voltage_swing == VOLTAGE_LEVEL_3) + training_lane |= DPCD_MAX_SWING_REACHED; + if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) + training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; - buf[0] = DPCD_SCRAMBLING_DISABLED | - DPCD_TRAINING_PATTERN_2; - exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - buf[0]); + dp->link_train.training_lane[lane] = training_lane; - for (lane = 0; lane < lane_count; lane++) { exynos_dp_set_lane_link_training(dp, dp->link_train.training_lane[lane], lane); - buf[lane] = dp->link_train.training_lane[lane]; - exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_LANE0_SET + lane, - buf[lane]); } - dp->link_train.lt_state = EQUALIZER_TRAINING; - } else { - exynos_dp_read_byte_from_dpcd(dp, - DPCD_ADDR_ADJUST_REQUEST_LANE0_1, - &data); - adjust_request[0] = data; - exynos_dp_read_byte_from_dpcd(dp, - DPCD_ADDR_ADJUST_REQUEST_LANE2_3, - &data); - adjust_request[1] = data; + exynos_dp_write_byte_to_dpcd(dp, + DPCD_ADDR_TRAINING_PATTERN_SET, + DPCD_SCRAMBLING_DISABLED | + DPCD_TRAINING_PATTERN_2); + + exynos_dp_write_bytes_to_dpcd(dp, + DPCD_ADDR_TRAINING_LANE0_SET, + lane_count, + dp->link_train.training_lane); + dev_info(dp->dev, "Link Training Clock Recovery success\n"); + dp->link_train.lt_state = EQUALIZER_TRAINING; + } else { for (lane = 0; lane < lane_count; lane++) { training_lane = exynos_dp_get_lane_link_training( dp, lane); + exynos_dp_read_bytes_from_dpcd(dp, + DPCD_ADDR_ADJUST_REQUEST_LANE0_1, + 2, adjust_request); voltage_swing = exynos_dp_get_adjust_request_voltage( adjust_request, lane); pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( adjust_request, lane); - if ((DPCD_VOLTAGE_SWING_GET(training_lane) == voltage_swing) && - (DPCD_PRE_EMPHASIS_GET(training_lane) == pre_emphasis)) - dp->link_train.cr_loop[lane]++; - dp->link_train.training_lane[lane] = training_lane; - } - if (exynos_dp_check_max_cr_loop(dp, voltage_swing) != 0) { - exynos_dp_reduce_link_rate(dp); - } else { - exynos_dp_get_adjust_train(dp, adjust_request); + if (voltage_swing == VOLTAGE_LEVEL_3 || + pre_emphasis == PRE_EMPHASIS_LEVEL_3) { + dev_err(dp->dev, "voltage or pre emphasis reached max level\n"); + goto reduce_link_rate; + } - for (lane = 0; lane < lane_count; lane++) { - exynos_dp_set_lane_link_training(dp, - dp->link_train.training_lane[lane], - lane); - buf[lane] = dp->link_train.training_lane[lane]; - exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_LANE0_SET + lane, - buf[lane]); + if ((DPCD_VOLTAGE_SWING_GET(training_lane) == + voltage_swing) && + (DPCD_PRE_EMPHASIS_GET(training_lane) == + pre_emphasis)) { + dp->link_train.cr_loop[lane]++; + if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP) { + dev_err(dp->dev, "CR Max loop\n"); + goto reduce_link_rate; + } } + + training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | + DPCD_PRE_EMPHASIS_SET(pre_emphasis); + + if (voltage_swing == VOLTAGE_LEVEL_3) + training_lane |= DPCD_MAX_SWING_REACHED; + if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) + training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; + + dp->link_train.training_lane[lane] = training_lane; + + exynos_dp_set_lane_link_training(dp, + dp->link_train.training_lane[lane], lane); } + + exynos_dp_write_bytes_to_dpcd(dp, + DPCD_ADDR_TRAINING_LANE0_SET, + lane_count, + dp->link_train.training_lane); } return 0; + +reduce_link_rate: + exynos_dp_reduce_link_rate(dp); + return -EIO; } static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) { - u8 link_status[6]; + u8 link_status[2]; + u8 link_align[3]; int lane; int lane_count; - u8 buf[5]; u32 reg; u8 adjust_request[2]; + u8 voltage_swing; + u8 pre_emphasis; + u8 training_lane; usleep_range(400, 401); - exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, - 6, link_status); lane_count = dp->link_train.lane_count; + exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, + 2, link_status); + if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { - adjust_request[0] = link_status[4]; - adjust_request[1] = link_status[5]; + link_align[0] = link_status[0]; + link_align[1] = link_status[1]; - if (exynos_dp_channel_eq_ok(link_status, lane_count) == 0) { + exynos_dp_read_byte_from_dpcd(dp, + DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, + &link_align[2]); + + for (lane = 0; lane < lane_count; lane++) { + exynos_dp_read_bytes_from_dpcd(dp, + DPCD_ADDR_ADJUST_REQUEST_LANE0_1, + 2, adjust_request); + voltage_swing = exynos_dp_get_adjust_request_voltage( + adjust_request, lane); + pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( + adjust_request, lane); + training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | + DPCD_PRE_EMPHASIS_SET(pre_emphasis); + + if (voltage_swing == VOLTAGE_LEVEL_3) + training_lane |= DPCD_MAX_SWING_REACHED; + if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) + training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; + + dp->link_train.training_lane[lane] = training_lane; + } + + if (exynos_dp_channel_eq_ok(link_align, lane_count) == 0) { /* traing pattern Set to Normal */ exynos_dp_training_pattern_dis(dp); @@ -596,39 +602,42 @@ static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) dp->link_train.lane_count = reg; dev_dbg(dp->dev, "final lane count = %.2x\n", dp->link_train.lane_count); + /* set enhanced mode if available */ exynos_dp_set_enhanced_mode(dp); - dp->link_train.lt_state = FINISHED; } else { /* not all locked */ dp->link_train.eq_loop++; if (dp->link_train.eq_loop > MAX_EQ_LOOP) { - exynos_dp_reduce_link_rate(dp); - } else { - exynos_dp_get_adjust_train(dp, adjust_request); - - for (lane = 0; lane < lane_count; lane++) { - exynos_dp_set_lane_link_training(dp, - dp->link_train.training_lane[lane], - lane); - buf[lane] = dp->link_train.training_lane[lane]; - exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_LANE0_SET + lane, - buf[lane]); - } + dev_err(dp->dev, "EQ Max loop\n"); + goto reduce_link_rate; } + + for (lane = 0; lane < lane_count; lane++) + exynos_dp_set_lane_link_training(dp, + dp->link_train.training_lane[lane], + lane); + + exynos_dp_write_bytes_to_dpcd(dp, + DPCD_ADDR_TRAINING_LANE0_SET, + lane_count, + dp->link_train.training_lane); } } else { - exynos_dp_reduce_link_rate(dp); + goto reduce_link_rate; } return 0; + +reduce_link_rate: + exynos_dp_reduce_link_rate(dp); + return -EIO; } static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp, - u8 *bandwidth) + u8 *bandwidth) { u8 data; @@ -641,7 +650,7 @@ static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp, } static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp, - u8 *lane_count) + u8 *lane_count) { u8 data; @@ -693,13 +702,7 @@ static void exynos_dp_init_training(struct exynos_dp_device *dp, static int exynos_dp_sw_link_training(struct exynos_dp_device *dp) { int retval = 0; - int training_finished; - - /* Turn off unnecessary lane */ - if (dp->link_train.lane_count == 1) - exynos_dp_set_analog_power_down(dp, CH1_BLOCK, 1); - - training_finished = 0; + int training_finished = 0; dp->link_train.lt_state = START; @@ -710,10 +713,14 @@ static int exynos_dp_sw_link_training(struct exynos_dp_device *dp) exynos_dp_link_start(dp); break; case CLOCK_RECOVERY: - exynos_dp_process_clock_recovery(dp); + retval = exynos_dp_process_clock_recovery(dp); + if (retval) + dev_err(dp->dev, "LT CR failed!\n"); break; case EQUALIZER_TRAINING: - exynos_dp_process_equalizer_training(dp); + retval = exynos_dp_process_equalizer_training(dp); + if (retval) + dev_err(dp->dev, "LT EQ failed!\n"); break; case FINISHED: training_finished = 1; @@ -872,40 +879,33 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) dp->dev = &pdev->dev; - dp->clock = clk_get(&pdev->dev, "dp"); + dp->clock = devm_clk_get(&pdev->dev, "dp"); if (IS_ERR(dp->clock)) { dev_err(&pdev->dev, "failed to get clock\n"); return PTR_ERR(dp->clock); } - clk_enable(dp->clock); + clk_prepare_enable(dp->clock); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get registers\n"); - ret = -EINVAL; - goto err_clock; - } dp->reg_base = devm_request_and_ioremap(&pdev->dev, res); if (!dp->reg_base) { dev_err(&pdev->dev, "failed to ioremap\n"); - ret = -ENOMEM; - goto err_clock; + return -ENOMEM; } dp->irq = platform_get_irq(pdev, 0); if (!dp->irq) { dev_err(&pdev->dev, "failed to get irq\n"); - ret = -ENODEV; - goto err_clock; + return -ENODEV; } ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0, "exynos-dp", dp); if (ret) { dev_err(&pdev->dev, "failed to request irq\n"); - goto err_clock; + return ret; } dp->video_info = pdata->video_info; @@ -917,7 +917,7 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) ret = exynos_dp_detect_hpd(dp); if (ret) { dev_err(&pdev->dev, "unable to detect hpd\n"); - goto err_clock; + return ret; } exynos_dp_handle_edid(dp); @@ -926,7 +926,7 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) dp->video_info->link_rate); if (ret) { dev_err(&pdev->dev, "unable to do link train\n"); - goto err_clock; + return ret; } exynos_dp_enable_scramble(dp, 1); @@ -940,17 +940,12 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) ret = exynos_dp_config_video(dp, dp->video_info); if (ret) { dev_err(&pdev->dev, "unable to config video\n"); - goto err_clock; + return ret; } platform_set_drvdata(pdev, dp); return 0; - -err_clock: - clk_put(dp->clock); - - return ret; } static int __devexit exynos_dp_remove(struct platform_device *pdev) @@ -961,8 +956,7 @@ static int __devexit exynos_dp_remove(struct platform_device *pdev) if (pdata && pdata->phy_exit) pdata->phy_exit(); - clk_disable(dp->clock); - clk_put(dp->clock); + clk_disable_unprepare(dp->clock); return 0; } @@ -977,7 +971,7 @@ static int exynos_dp_suspend(struct device *dev) if (pdata && pdata->phy_exit) pdata->phy_exit(); - clk_disable(dp->clock); + clk_disable_unprepare(dp->clock); return 0; } @@ -991,7 +985,7 @@ static int exynos_dp_resume(struct device *dev) if (pdata && pdata->phy_init) pdata->phy_init(); - clk_enable(dp->clock); + clk_prepare_enable(dp->clock); exynos_dp_init_dp(dp); diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/video/exynos/exynos_dp_core.h index 8526e548c385..57b8a6531c0e 100644 --- a/drivers/video/exynos/exynos_dp_core.h +++ b/drivers/video/exynos/exynos_dp_core.h @@ -43,7 +43,7 @@ void exynos_dp_init_interrupt(struct exynos_dp_device *dp); void exynos_dp_reset(struct exynos_dp_device *dp); void exynos_dp_swreset(struct exynos_dp_device *dp); void exynos_dp_config_interrupt(struct exynos_dp_device *dp); -u32 exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp); +enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp); void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable); void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp, enum analog_power_block block, @@ -105,7 +105,7 @@ u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp); u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp); u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp); void exynos_dp_reset_macro(struct exynos_dp_device *dp); -int exynos_dp_init_video(struct exynos_dp_device *dp); +void exynos_dp_init_video(struct exynos_dp_device *dp); void exynos_dp_set_video_color_format(struct exynos_dp_device *dp, u32 color_depth, @@ -144,7 +144,7 @@ void exynos_dp_disable_scrambling(struct exynos_dp_device *dp); #define DPCD_ADDR_TRAINING_PATTERN_SET 0x0102 #define DPCD_ADDR_TRAINING_LANE0_SET 0x0103 #define DPCD_ADDR_LANE0_1_STATUS 0x0202 -#define DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED 0x0204 +#define DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED 0x0204 #define DPCD_ADDR_ADJUST_REQUEST_LANE0_1 0x0206 #define DPCD_ADDR_ADJUST_REQUEST_LANE2_3 0x0207 #define DPCD_ADDR_TEST_REQUEST 0x0218 diff --git a/drivers/video/exynos/exynos_dp_reg.c b/drivers/video/exynos/exynos_dp_reg.c index 2db5b9aa250a..3f5ca8a0d5ea 100644 --- a/drivers/video/exynos/exynos_dp_reg.c +++ b/drivers/video/exynos/exynos_dp_reg.c @@ -77,7 +77,7 @@ void exynos_dp_init_analog_param(struct exynos_dp_device *dp) writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_3); reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM | - TX_CUR1_2X | TX_CUR_8_MA; + TX_CUR1_2X | TX_CUR_16_MA; writel(reg, dp->reg_base + EXYNOS_DP_PLL_FILTER_CTL_1); reg = CH3_AMP_400_MV | CH2_AMP_400_MV | @@ -148,9 +148,6 @@ void exynos_dp_reset(struct exynos_dp_device *dp) writel(0x2, dp->reg_base + EXYNOS_DP_M_AUD_GEN_FILTER_TH); writel(0x00000101, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); - - exynos_dp_init_analog_param(dp); - exynos_dp_init_interrupt(dp); } void exynos_dp_swreset(struct exynos_dp_device *dp) @@ -179,7 +176,7 @@ void exynos_dp_config_interrupt(struct exynos_dp_device *dp) writel(reg, dp->reg_base + EXYNOS_DP_INT_STA_MASK); } -u32 exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp) +enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp) { u32 reg; @@ -401,6 +398,7 @@ int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp) { int reg; int retval = 0; + int timeout_loop = 0; /* Enable AUX CH operation */ reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2); @@ -409,8 +407,15 @@ int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp) /* Is AUX CH command reply received? */ reg = readl(dp->reg_base + EXYNOS_DP_INT_STA); - while (!(reg & RPLY_RECEIV)) + while (!(reg & RPLY_RECEIV)) { + timeout_loop++; + if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { + dev_err(dp->dev, "AUX CH command reply failed!\n"); + return -ETIMEDOUT; + } reg = readl(dp->reg_base + EXYNOS_DP_INT_STA); + usleep_range(10, 11); + } /* Clear interrupt source for AUX CH command reply */ writel(RPLY_RECEIV, dp->reg_base + EXYNOS_DP_INT_STA); @@ -471,7 +476,8 @@ int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp, if (retval == 0) break; else - dev_err(dp->dev, "Aux Transaction fail!\n"); + dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", + __func__); } return retval; @@ -511,7 +517,8 @@ int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp, if (retval == 0) break; else - dev_err(dp->dev, "Aux Transaction fail!\n"); + dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", + __func__); } /* Read data buffer */ @@ -575,7 +582,8 @@ int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp, if (retval == 0) break; else - dev_err(dp->dev, "Aux Transaction fail!\n"); + dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", + __func__); } start_offset += cur_data_count; @@ -632,7 +640,8 @@ int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp, if (retval == 0) break; else - dev_err(dp->dev, "Aux Transaction fail!\n"); + dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", + __func__); } for (cur_data_idx = 0; cur_data_idx < cur_data_count; @@ -677,7 +686,7 @@ int exynos_dp_select_i2c_device(struct exynos_dp_device *dp, /* Start AUX transaction */ retval = exynos_dp_start_aux_transaction(dp); if (retval != 0) - dev_err(dp->dev, "Aux Transaction fail!\n"); + dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); return retval; } @@ -717,7 +726,8 @@ int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp, if (retval == 0) break; else - dev_err(dp->dev, "Aux Transaction fail!\n"); + dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", + __func__); } /* Read data */ @@ -777,7 +787,9 @@ int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp, if (retval == 0) break; else - dev_err(dp->dev, "Aux Transaction fail!\n"); + dev_dbg(dp->dev, + "%s: Aux Transaction fail!\n", + __func__); } /* Check if Rx sends defer */ reg = readl(dp->reg_base + EXYNOS_DP_AUX_RX_COMM); @@ -883,7 +895,9 @@ void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level) { u32 reg; - reg = level << PRE_EMPHASIS_SET_SHIFT; + reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL); + reg &= ~PRE_EMPHASIS_SET_MASK; + reg |= level << PRE_EMPHASIS_SET_SHIFT; writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL); } @@ -891,7 +905,9 @@ void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level) { u32 reg; - reg = level << PRE_EMPHASIS_SET_SHIFT; + reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL); + reg &= ~PRE_EMPHASIS_SET_MASK; + reg |= level << PRE_EMPHASIS_SET_SHIFT; writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL); } @@ -899,7 +915,9 @@ void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level) { u32 reg; - reg = level << PRE_EMPHASIS_SET_SHIFT; + reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL); + reg &= ~PRE_EMPHASIS_SET_MASK; + reg |= level << PRE_EMPHASIS_SET_SHIFT; writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL); } @@ -907,7 +925,9 @@ void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level) { u32 reg; - reg = level << PRE_EMPHASIS_SET_SHIFT; + reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL); + reg &= ~PRE_EMPHASIS_SET_MASK; + reg |= level << PRE_EMPHASIS_SET_SHIFT; writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL); } @@ -994,7 +1014,7 @@ void exynos_dp_reset_macro(struct exynos_dp_device *dp) writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST); } -int exynos_dp_init_video(struct exynos_dp_device *dp) +void exynos_dp_init_video(struct exynos_dp_device *dp) { u32 reg; @@ -1012,8 +1032,6 @@ int exynos_dp_init_video(struct exynos_dp_device *dp) reg = VID_HRES_TH(2) | VID_VRES_TH(0); writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8); - - return 0; } void exynos_dp_set_video_color_format(struct exynos_dp_device *dp, diff --git a/drivers/video/exynos/exynos_dp_reg.h b/drivers/video/exynos/exynos_dp_reg.h index 125b27cd57ae..1f2f014cfe88 100644 --- a/drivers/video/exynos/exynos_dp_reg.h +++ b/drivers/video/exynos/exynos_dp_reg.h @@ -187,7 +187,7 @@ #define PD_RING_OSC (0x1 << 6) #define AUX_TERMINAL_CTRL_50_OHM (0x2 << 4) #define TX_CUR1_2X (0x1 << 2) -#define TX_CUR_8_MA (0x2 << 0) +#define TX_CUR_16_MA (0x3 << 0) /* EXYNOS_DP_TX_AMP_TUNING_CTL */ #define CH3_AMP_400_MV (0x0 << 24) @@ -285,6 +285,7 @@ #define SW_TRAINING_PATTERN_SET_NORMAL (0x0 << 0) /* EXYNOS_DP_LN0_LINK_TRAINING_CTL */ +#define PRE_EMPHASIS_SET_MASK (0x3 << 3) #define PRE_EMPHASIS_SET_SHIFT (3) /* EXYNOS_DP_DEBUG_CTL */ diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c index 663c308d0e73..07d70a3a628b 100644 --- a/drivers/video/exynos/exynos_mipi_dsi.c +++ b/drivers/video/exynos/exynos_mipi_dsi.c @@ -205,7 +205,8 @@ int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev) return 0; } -struct mipi_dsim_ddi *exynos_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv) +static struct mipi_dsim_ddi *exynos_mipi_dsi_find_lcd_device( + struct mipi_dsim_lcd_driver *lcd_drv) { struct mipi_dsim_ddi *dsim_ddi, *next; struct mipi_dsim_lcd_device *lcd_dev; @@ -265,7 +266,8 @@ int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv) } -struct mipi_dsim_ddi *exynos_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim, +static struct mipi_dsim_ddi *exynos_mipi_dsi_bind_lcd_ddi( + struct mipi_dsim_device *dsim, const char *name) { struct mipi_dsim_ddi *dsim_ddi, *next; @@ -373,6 +375,7 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev) dsim->clock = clk_get(&pdev->dev, "dsim0"); if (IS_ERR(dsim->clock)) { dev_err(&pdev->dev, "failed to get dsim clock source\n"); + ret = -ENODEV; goto err_clock_get; } @@ -381,6 +384,7 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "failed to get io memory region\n"); + ret = -ENODEV; goto err_platform_get; } @@ -405,6 +409,7 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev) dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name); if (!dsim_ddi) { dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n"); + ret = -EINVAL; goto err_bind; } diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.c b/drivers/video/exynos/exynos_mipi_dsi_common.c index 47b533a183be..3cd29a4fc10a 100644 --- a/drivers/video/exynos/exynos_mipi_dsi_common.c +++ b/drivers/video/exynos/exynos_mipi_dsi_common.c @@ -79,11 +79,6 @@ irqreturn_t exynos_mipi_dsi_interrupt_handler(int irq, void *dev_id) struct mipi_dsim_device *dsim = dev_id; unsigned int intsrc, intmsk; - if (dsim == NULL) { - dev_err(dsim->dev, "%s: wrong parameter\n", __func__); - return IRQ_NONE; - } - intsrc = exynos_mipi_dsi_read_interrupt(dsim); intmsk = exynos_mipi_dsi_read_interrupt_mask(dsim); intmsk = ~intmsk & intsrc; @@ -288,9 +283,6 @@ int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id, mutex_unlock(&dsim->lock); return -EINVAL; } - - mutex_unlock(&dsim->lock); - return 0; } static unsigned int exynos_mipi_dsi_long_data_rd(struct mipi_dsim_device *dsim, diff --git a/drivers/video/fb-puv3.c b/drivers/video/fb-puv3.c index 60a787fa32cf..7d106f1f4906 100644 --- a/drivers/video/fb-puv3.c +++ b/drivers/video/fb-puv3.c @@ -653,9 +653,8 @@ int unifb_mmap(struct fb_info *info, vma->vm_page_prot)) return -EAGAIN; - vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ + /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */ return 0; - } static struct fb_ops unifb_ops = { diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c index 64cda560c488..88cad6b8b479 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c @@ -166,7 +166,7 @@ static const struct address_space_operations fb_deferred_io_aops = { static int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma) { vma->vm_ops = &fb_deferred_io_vm_ops; - vma->vm_flags |= ( VM_RESERVED | VM_DONTEXPAND ); + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; if (!(info->flags & FBINFO_VIRTFB)) vma->vm_flags |= VM_IO; vma->vm_private_data = info; diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 0dff12a1daef..3ff0105a496a 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1410,8 +1410,7 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) return -EINVAL; off += start; vma->vm_pgoff = off >> PAGE_SHIFT; - /* This is an IO map - tell maydump to skip this VMA */ - vma->vm_flags |= VM_IO | VM_RESERVED; + /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by io_remap_pfn_range()*/ vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); fb_pgprotect(file, vma, off); if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index 458c00664ade..ede9e55413f8 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -1501,8 +1501,8 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) unsigned int i; int ret; - data = dma_alloc_coherent(&pdev->dev, sizeof(struct fsl_diu_data), - &dma_addr, GFP_DMA | __GFP_ZERO); + data = dmam_alloc_coherent(&pdev->dev, sizeof(struct fsl_diu_data), + &dma_addr, GFP_DMA | __GFP_ZERO); if (!data) return -ENOMEM; data->dma_addr = dma_addr; @@ -1628,9 +1628,6 @@ error: iounmap(data->diu_reg); - dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), data, - data->dma_addr); - return ret; } @@ -1648,9 +1645,6 @@ static int fsl_diu_remove(struct platform_device *pdev) iounmap(data->diu_reg); - dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), data, - data->dma_addr); - return 0; } diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index 7e7b7a9ba274..3dad31975db8 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c @@ -20,6 +20,7 @@ #include <linux/kernel.h> #include <linux/mm.h> #include <linux/module.h> +#include <linux/io.h> #ifdef CONFIG_X86 #include <asm/mtrr.h> @@ -28,7 +29,6 @@ #include <asm/addrspace.h> #endif #include <asm/byteorder.h> -#include <asm/io.h> #include <asm/tlbflush.h> #include <video/gbe.h> @@ -1024,7 +1024,7 @@ static int gbefb_mmap(struct fb_info *info, pgprot_val(vma->vm_page_prot) = pgprot_fb(pgprot_val(vma->vm_page_prot)); - vma->vm_flags |= VM_IO | VM_RESERVED; + /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */ /* look for the starting tile */ tile = &gbe_tiles.cpu[offset >> TILE_SHIFT]; @@ -1156,7 +1156,8 @@ static int __devinit gbefb_probe(struct platform_device *p_dev) goto out_release_framebuffer; } - gbe = (struct sgi_gbe *) ioremap(GBE_BASE, sizeof(struct sgi_gbe)); + gbe = (struct sgi_gbe *) devm_ioremap(&p_dev->dev, GBE_BASE, + sizeof(struct sgi_gbe)); if (!gbe) { printk(KERN_ERR "gbefb: couldn't map mmio region\n"); ret = -ENXIO; @@ -1170,12 +1171,13 @@ static int __devinit gbefb_probe(struct platform_device *p_dev) if (!gbe_tiles.cpu) { printk(KERN_ERR "gbefb: couldn't allocate tiles table\n"); ret = -ENOMEM; - goto out_unmap; + goto out_release_mem_region; } if (gbe_mem_phys) { /* memory was allocated at boot time */ - gbe_mem = ioremap_nocache(gbe_mem_phys, gbe_mem_size); + gbe_mem = devm_ioremap_nocache(&p_dev->dev, gbe_mem_phys, + gbe_mem_size); if (!gbe_mem) { printk(KERN_ERR "gbefb: couldn't map framebuffer\n"); ret = -ENOMEM; @@ -1241,13 +1243,9 @@ static int __devinit gbefb_probe(struct platform_device *p_dev) out_gbe_unmap: if (gbe_dma_addr) dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys); - else - iounmap(gbe_mem); out_tiles_free: dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t), (void *)gbe_tiles.cpu, gbe_tiles.dma); -out_unmap: - iounmap(gbe); out_release_mem_region: release_mem_region(GBE_BASE, sizeof(struct sgi_gbe)); out_release_framebuffer: @@ -1264,12 +1262,9 @@ static int __devexit gbefb_remove(struct platform_device* p_dev) gbe_turn_off(); if (gbe_dma_addr) dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys); - else - iounmap(gbe_mem); dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t), (void *)gbe_tiles.cpu, gbe_tiles.dma); release_mem_region(GBE_BASE, sizeof(struct sgi_gbe)); - iounmap(gbe); gbefb_remove_sysfs(&p_dev->dev); framebuffer_release(info); diff --git a/drivers/video/geode/gx1fb_core.c b/drivers/video/geode/gx1fb_core.c index 5a5d0928df33..265c5ed59ade 100644 --- a/drivers/video/geode/gx1fb_core.c +++ b/drivers/video/geode/gx1fb_core.c @@ -29,7 +29,7 @@ static int crt_option = 1; static char panel_option[32] = ""; /* Modes relevant to the GX1 (taken from modedb.c) */ -static const struct fb_videomode __devinitdata gx1_modedb[] = { +static const struct fb_videomode __devinitconst gx1_modedb[] = { /* 640x480-60 VESA */ { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, diff --git a/drivers/video/gxt4500.c b/drivers/video/gxt4500.c index 0fad23f810a3..0e9afa41d163 100644 --- a/drivers/video/gxt4500.c +++ b/drivers/video/gxt4500.c @@ -156,7 +156,7 @@ struct gxt4500_par { static char *mode_option; /* default mode: 1280x1024 @ 60 Hz, 8 bpp */ -static const struct fb_videomode defaultmode __devinitdata = { +static const struct fb_videomode defaultmode __devinitconst = { .refresh = 60, .xres = 1280, .yres = 1024, @@ -581,7 +581,7 @@ static int gxt4500_blank(int blank, struct fb_info *info) return 0; } -static const struct fb_fix_screeninfo gxt4500_fix __devinitdata = { +static const struct fb_fix_screeninfo gxt4500_fix __devinitconst = { .id = "IBM GXT4500P", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_PSEUDOCOLOR, diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c index ebf8495ff198..7324865f965f 100644 --- a/drivers/video/hpfb.c +++ b/drivers/video/hpfb.c @@ -210,6 +210,7 @@ static int __devinit hpfb_init_one(unsigned long phys_base, unsigned long virt_base) { unsigned long fboff, fb_width, fb_height, fb_start; + int ret; fb_regs = virt_base; fboff = (in_8(fb_regs + HPFB_FBOMSB) << 8) | in_8(fb_regs + HPFB_FBOLSB); @@ -290,19 +291,29 @@ static int __devinit hpfb_init_one(unsigned long phys_base, fb_info.var = hpfb_defined; fb_info.screen_base = (char *)fb_start; - fb_alloc_cmap(&fb_info.cmap, 1 << hpfb_defined.bits_per_pixel, 0); + ret = fb_alloc_cmap(&fb_info.cmap, 1 << hpfb_defined.bits_per_pixel, 0); + if (ret < 0) + goto unmap_screen_base; - if (register_framebuffer(&fb_info) < 0) { - fb_dealloc_cmap(&fb_info.cmap); - iounmap(fb_info.screen_base); - fb_info.screen_base = NULL; - return 1; - } + ret = register_framebuffer(&fb_info); + if (ret < 0) + goto dealloc_cmap; printk(KERN_INFO "fb%d: %s frame buffer device\n", fb_info.node, fb_info.fix.id); return 0; + +dealloc_cmap: + fb_dealloc_cmap(&fb_info.cmap); + +unmap_screen_base: + if (fb_info.screen_base) { + iounmap(fb_info.screen_base); + fb_info.screen_base = NULL; + } + + return ret; } /* @@ -345,6 +356,9 @@ static void __devexit hpfb_remove_one(struct dio_dev *d) if (d->scode >= DIOII_SCBASE) iounmap((void *)fb_regs); release_mem_region(d->resource.start, resource_size(&d->resource)); + fb_dealloc_cmap(&fb_info.cmap); + if (fb_info.screen_base) + iounmap(fb_info.screen_base); } static struct dio_device_id hpfb_dio_tbl[] = { diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index b83f36190cae..5c067816a81d 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -97,7 +97,7 @@ static int i810fb_blank (int blank_mode, struct fb_info *info); static void i810fb_release_resource (struct fb_info *info, struct i810fb_par *par); /* PCI */ -static const char *i810_pci_list[] __devinitdata = { +static const char * const i810_pci_list[] __devinitconst = { "Intel(R) 810 Framebuffer Device" , "Intel(R) 810-DC100 Framebuffer Device" , "Intel(R) 810E Framebuffer Device" , diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 53ffdfc82a75..cf2688de0832 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -803,6 +803,7 @@ static int __init imxfb_probe(struct platform_device *pdev) fbi->regs = ioremap(res->start, resource_size(res)); if (fbi->regs == NULL) { dev_err(&pdev->dev, "Cannot map frame buffer registers\n"); + ret = -ENOMEM; goto failed_ioremap; } diff --git a/drivers/video/jz4740_fb.c b/drivers/video/jz4740_fb.c index de366937c933..4d25711b9982 100644 --- a/drivers/video/jz4740_fb.c +++ b/drivers/video/jz4740_fb.c @@ -136,7 +136,7 @@ struct jzfb { uint32_t pseudo_palette[16]; }; -static const struct fb_fix_screeninfo jzfb_fix __devinitdata = { +static const struct fb_fix_screeninfo jzfb_fix __devinitconst = { .id = "JZ4740 FB", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_TRUECOLOR, @@ -632,23 +632,10 @@ static int __devinit jzfb_probe(struct platform_device *pdev) return -ENXIO; } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "Failed to get register memory resource\n"); - return -ENXIO; - } - - mem = request_mem_region(mem->start, resource_size(mem), pdev->name); - if (!mem) { - dev_err(&pdev->dev, "Failed to request register memory region\n"); - return -EBUSY; - } - fb = framebuffer_alloc(sizeof(struct jzfb), &pdev->dev); if (!fb) { dev_err(&pdev->dev, "Failed to allocate framebuffer device\n"); - ret = -ENOMEM; - goto err_release_mem_region; + return -ENOMEM; } fb->fbops = &jzfb_ops; @@ -657,27 +644,26 @@ static int __devinit jzfb_probe(struct platform_device *pdev) jzfb = fb->par; jzfb->pdev = pdev; jzfb->pdata = pdata; - jzfb->mem = mem; - jzfb->ldclk = clk_get(&pdev->dev, "lcd"); + jzfb->ldclk = devm_clk_get(&pdev->dev, "lcd"); if (IS_ERR(jzfb->ldclk)) { ret = PTR_ERR(jzfb->ldclk); dev_err(&pdev->dev, "Failed to get lcd clock: %d\n", ret); goto err_framebuffer_release; } - jzfb->lpclk = clk_get(&pdev->dev, "lcd_pclk"); + jzfb->lpclk = devm_clk_get(&pdev->dev, "lcd_pclk"); if (IS_ERR(jzfb->lpclk)) { ret = PTR_ERR(jzfb->lpclk); dev_err(&pdev->dev, "Failed to get lcd pixel clock: %d\n", ret); - goto err_put_ldclk; + goto err_framebuffer_release; } - jzfb->base = ioremap(mem->start, resource_size(mem)); + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + jzfb->base = devm_request_and_ioremap(&pdev->dev, mem); if (!jzfb->base) { - dev_err(&pdev->dev, "Failed to ioremap register memory region\n"); ret = -EBUSY; - goto err_put_lpclk; + goto err_framebuffer_release; } platform_set_drvdata(pdev, jzfb); @@ -693,7 +679,7 @@ static int __devinit jzfb_probe(struct platform_device *pdev) ret = jzfb_alloc_devmem(jzfb); if (ret) { dev_err(&pdev->dev, "Failed to allocate video memory\n"); - goto err_iounmap; + goto err_framebuffer_release; } fb->fix = jzfb_fix; @@ -734,16 +720,8 @@ err_free_devmem: fb_dealloc_cmap(&fb->cmap); jzfb_free_devmem(jzfb); -err_iounmap: - iounmap(jzfb->base); -err_put_lpclk: - clk_put(jzfb->lpclk); -err_put_ldclk: - clk_put(jzfb->ldclk); err_framebuffer_release: framebuffer_release(fb); -err_release_mem_region: - release_mem_region(mem->start, resource_size(mem)); return ret; } @@ -756,17 +734,11 @@ static int __devexit jzfb_remove(struct platform_device *pdev) jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb)); jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb)); - iounmap(jzfb->base); - release_mem_region(jzfb->mem->start, resource_size(jzfb->mem)); - fb_dealloc_cmap(&jzfb->fb->cmap); jzfb_free_devmem(jzfb); platform_set_drvdata(pdev, NULL); - clk_put(jzfb->lpclk); - clk_put(jzfb->ldclk); - framebuffer_release(jzfb->fb); return 0; diff --git a/drivers/video/mb862xx/mb862xxfbdrv.c b/drivers/video/mb862xx/mb862xxfbdrv.c index 57d940be5f3d..d68e332aa21c 100644 --- a/drivers/video/mb862xx/mb862xxfbdrv.c +++ b/drivers/video/mb862xx/mb862xxfbdrv.c @@ -1052,12 +1052,14 @@ static int __devinit mb862xx_pci_probe(struct pci_dev *pdev, break; default: /* should never occur */ + ret = -EIO; goto rel_reg; } par->fb_base = ioremap(par->fb_base_phys, par->mapped_vram); if (par->fb_base == NULL) { dev_err(dev, "Cannot map framebuffer\n"); + ret = -EIO; goto rel_reg; } @@ -1073,11 +1075,13 @@ static int __devinit mb862xx_pci_probe(struct pci_dev *pdev, dev_dbg(dev, "mmio phys 0x%llx 0x%lx\n", (unsigned long long)par->mmio_base_phys, (ulong)par->mmio_len); - if (mb862xx_pci_gdc_init(par)) + ret = mb862xx_pci_gdc_init(par); + if (ret) goto io_unmap; - if (request_irq(par->irq, mb862xx_intr, IRQF_SHARED, - DRV_NAME, (void *)par)) { + ret = request_irq(par->irq, mb862xx_intr, IRQF_SHARED, + DRV_NAME, (void *)par); + if (ret) { dev_err(dev, "Cannot request irq\n"); goto io_unmap; } diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c index 85e4f44bfa61..6563e50413c1 100644 --- a/drivers/video/mbx/mbxfb.c +++ b/drivers/video/mbx/mbxfb.c @@ -26,8 +26,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/uaccess.h> - -#include <asm/io.h> +#include <linux/io.h> #include <video/mbxfb.h> @@ -939,8 +938,9 @@ static int __devinit mbxfb_probe(struct platform_device *dev) } mfbi->reg_phys_addr = mfbi->reg_res->start; - mfbi->reg_virt_addr = ioremap_nocache(mfbi->reg_phys_addr, - res_size(mfbi->reg_req)); + mfbi->reg_virt_addr = devm_ioremap_nocache(&dev->dev, + mfbi->reg_phys_addr, + res_size(mfbi->reg_req)); if (!mfbi->reg_virt_addr) { dev_err(&dev->dev, "failed to ioremap Marathon registers\n"); ret = -EINVAL; @@ -948,12 +948,12 @@ static int __devinit mbxfb_probe(struct platform_device *dev) } virt_base_2700 = mfbi->reg_virt_addr; - mfbi->fb_virt_addr = ioremap_nocache(mfbi->fb_phys_addr, - res_size(mfbi->fb_req)); + mfbi->fb_virt_addr = devm_ioremap_nocache(&dev->dev, mfbi->fb_phys_addr, + res_size(mfbi->fb_req)); if (!mfbi->fb_virt_addr) { dev_err(&dev->dev, "failed to ioremap frame buffer\n"); ret = -EINVAL; - goto err4; + goto err3; } fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000); @@ -971,7 +971,7 @@ static int __devinit mbxfb_probe(struct platform_device *dev) if (ret < 0) { dev_err(&dev->dev, "fb_alloc_cmap failed\n"); ret = -EINVAL; - goto err5; + goto err3; } platform_set_drvdata(dev, fbi); @@ -996,10 +996,6 @@ static int __devinit mbxfb_probe(struct platform_device *dev) err6: fb_dealloc_cmap(&fbi->cmap); -err5: - iounmap(mfbi->fb_virt_addr); -err4: - iounmap(mfbi->reg_virt_addr); err3: release_mem_region(mfbi->reg_res->start, res_size(mfbi->reg_res)); err2: @@ -1026,10 +1022,7 @@ static int __devexit mbxfb_remove(struct platform_device *dev) if (mfbi->platform_remove) mfbi->platform_remove(fbi); - if (mfbi->fb_virt_addr) - iounmap(mfbi->fb_virt_addr); - if (mfbi->reg_virt_addr) - iounmap(mfbi->reg_virt_addr); + if (mfbi->reg_req) release_mem_region(mfbi->reg_req->start, res_size(mfbi->reg_req)); diff --git a/drivers/video/msm/mddi.c b/drivers/video/msm/mddi.c index bf73f0480061..35ac9e8bee63 100644 --- a/drivers/video/msm/mddi.c +++ b/drivers/video/msm/mddi.c @@ -26,9 +26,6 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/sched.h> -#include <mach/msm_iomap.h> -#include <mach/irqs.h> -#include <mach/board.h> #include <linux/platform_data/video-msm_fb.h> #include "mddi_hw.h" diff --git a/drivers/video/msm/mddi_client_nt35399.c b/drivers/video/msm/mddi_client_nt35399.c index d7a5bf84fb2a..f96df32e5509 100644 --- a/drivers/video/msm/mddi_client_nt35399.c +++ b/drivers/video/msm/mddi_client_nt35399.c @@ -189,8 +189,9 @@ static int mddi_nt35399_probe(struct platform_device *pdev) int ret; - struct panel_info *panel = kzalloc(sizeof(struct panel_info), - GFP_KERNEL); + struct panel_info *panel = devm_kzalloc(&pdev->dev, + sizeof(struct panel_info), + GFP_KERNEL); printk(KERN_DEBUG "%s: enter.\n", __func__); @@ -233,7 +234,6 @@ static int mddi_nt35399_remove(struct platform_device *pdev) struct panel_info *panel = platform_get_drvdata(pdev); setup_vsync(panel, 0); - kfree(panel); return 0; } diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c index 2e0f3bab6114..f2566c19e71c 100644 --- a/drivers/video/msm/mdp.c +++ b/drivers/video/msm/mdp.c @@ -25,7 +25,6 @@ #include <linux/major.h> #include <linux/slab.h> -#include <mach/msm_iomap.h> #include <linux/platform_data/video-msm_fb.h> #include <linux/platform_device.h> #include <linux/export.h> diff --git a/drivers/video/msm/mdp_hw.h b/drivers/video/msm/mdp_hw.h index a0bacf581b32..35848d741001 100644 --- a/drivers/video/msm/mdp_hw.h +++ b/drivers/video/msm/mdp_hw.h @@ -15,7 +15,6 @@ #ifndef _MDP_HW_H_ #define _MDP_HW_H_ -#include <mach/msm_iomap.h> #include <linux/platform_data/video-msm_fb.h> struct mdp_info { diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index d7381088a180..ce1d452464ed 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -1568,7 +1568,8 @@ static int mx3fb_remove(struct platform_device *dev) static struct platform_driver mx3fb_driver = { .driver = { - .name = MX3FB_NAME, + .name = MX3FB_NAME, + .owner = THIS_MODULE, }, .probe = mx3fb_probe, .remove = mx3fb_remove, diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c index 93387555337e..475dfee82c4a 100644 --- a/drivers/video/nuc900fb.c +++ b/drivers/video/nuc900fb.c @@ -387,7 +387,7 @@ static int nuc900fb_init_registers(struct fb_info *info) * The buffer should be a non-cached, non-buffered, memory region * to allow palette and pixel writes without flushing the cache. */ -static int __init nuc900fb_map_video_memory(struct fb_info *info) +static int __devinit nuc900fb_map_video_memory(struct fb_info *info) { struct nuc900fb_info *fbi = info->par; dma_addr_t map_dma; diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c index 9f1d23c319cb..f349ee6f0cea 100644 --- a/drivers/video/omap/hwa742.c +++ b/drivers/video/omap/hwa742.c @@ -27,7 +27,6 @@ #include <linux/clk.h> #include <linux/interrupt.h> -#include <plat/dma.h> #include "omapfb.h" #define HWA742_REV_CODE_REG 0x0 diff --git a/drivers/video/omap/lcd_palmte.c b/drivers/video/omap/lcd_palmte.c index 88c31eb0cd6c..ff4fb624b904 100644 --- a/drivers/video/omap/lcd_palmte.c +++ b/drivers/video/omap/lcd_palmte.c @@ -23,7 +23,6 @@ #include <linux/platform_device.h> #include <linux/io.h> -#include <plat/fpga.h> #include "omapfb.h" static int palmte_panel_init(struct lcd_panel *panel, diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index f54b463709e9..4351c438b76f 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c @@ -131,15 +131,6 @@ static void omapfb_rqueue_unlock(struct omapfb_device *fbdev) * LCD controller and LCD DMA * --------------------------------------------------------------------------- */ -/* Lookup table to map elem size to elem type. */ -static const int dma_elem_type[] = { - 0, - OMAP_DMA_DATA_TYPE_S8, - OMAP_DMA_DATA_TYPE_S16, - 0, - OMAP_DMA_DATA_TYPE_S32, -}; - /* * Allocate resources needed for LCD controller and LCD DMA operations. Video * memory is allocated from system memory according to the virtual display diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c index eaeed4340e04..c835aa70f96f 100644 --- a/drivers/video/omap2/displays/panel-acx565akm.c +++ b/drivers/video/omap2/displays/panel-acx565akm.c @@ -600,6 +600,9 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev) mutex_lock(&md->mutex); + omapdss_sdi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_sdi_set_datapairs(dssdev, dssdev->phy.sdi.datapairs); + r = omapdss_sdi_display_enable(dssdev); if (r) { pr_err("%s sdi enable failed\n", __func__); @@ -731,18 +734,9 @@ static int acx_panel_resume(struct omap_dss_device *dssdev) static void acx_panel_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - int r; - - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) - omapdss_sdi_display_disable(dssdev); + omapdss_sdi_set_timings(dssdev, timings); dssdev->panel.timings = *timings; - - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - r = omapdss_sdi_display_enable(dssdev); - if (r) - dev_err(&dssdev->dev, "%s enable failed\n", __func__); - } } static int acx_panel_check_timings(struct omap_dss_device *dssdev, diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index bc5af2500eb9..88295c526815 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c @@ -545,6 +545,8 @@ struct panel_drv_data { struct omap_dss_device *dssdev; struct panel_config *panel_config; + + struct mutex lock; }; static inline struct panel_generic_dpi_data @@ -563,6 +565,9 @@ static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) goto err0; @@ -634,6 +639,8 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) drv_data->dssdev = dssdev; drv_data->panel_config = panel_config; + mutex_init(&drv_data->lock); + dev_set_drvdata(&dssdev->dev, drv_data); return 0; @@ -652,56 +659,108 @@ static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev) static int generic_dpi_panel_enable(struct omap_dss_device *dssdev) { - int r = 0; + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + int r; + + mutex_lock(&drv_data->lock); r = generic_dpi_panel_power_on(dssdev); if (r) - return r; + goto err; dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; +err: + mutex_unlock(&drv_data->lock); - return 0; + return r; } static void generic_dpi_panel_disable(struct omap_dss_device *dssdev) { + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&drv_data->lock); + generic_dpi_panel_power_off(dssdev); dssdev->state = OMAP_DSS_DISPLAY_DISABLED; + + mutex_unlock(&drv_data->lock); } static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev) { + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&drv_data->lock); + generic_dpi_panel_power_off(dssdev); dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; + mutex_unlock(&drv_data->lock); + return 0; } static int generic_dpi_panel_resume(struct omap_dss_device *dssdev) { - int r = 0; + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + int r; + + mutex_lock(&drv_data->lock); r = generic_dpi_panel_power_on(dssdev); if (r) - return r; + goto err; dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - return 0; +err: + mutex_unlock(&drv_data->lock); + + return r; } static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - dpi_set_timings(dssdev, timings); + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&drv_data->lock); + + omapdss_dpi_set_timings(dssdev, timings); + + dssdev->panel.timings = *timings; + + mutex_unlock(&drv_data->lock); +} + +static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&drv_data->lock); + + *timings = dssdev->panel.timings; + + mutex_unlock(&drv_data->lock); } static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - return dpi_check_timings(dssdev, timings); + struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); + int r; + + mutex_lock(&drv_data->lock); + + r = dpi_check_timings(dssdev, timings); + + mutex_unlock(&drv_data->lock); + + return r; } static struct omap_dss_driver dpi_driver = { @@ -714,6 +773,7 @@ static struct omap_dss_driver dpi_driver = { .resume = generic_dpi_panel_resume, .set_timings = generic_dpi_panel_set_timings, + .get_timings = generic_dpi_panel_get_timings, .check_timings = generic_dpi_panel_check_timings, .driver = { diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c index 802807798846..90c1cabf244e 100644 --- a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c +++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c @@ -55,6 +55,9 @@ static int lb035q02_panel_power_on(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) goto err0; diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c index e6c115373c00..3fc5ad081a21 100644 --- a/drivers/video/omap2/displays/panel-n8x0.c +++ b/drivers/video/omap2/displays/panel-n8x0.c @@ -150,11 +150,17 @@ static void blizzard_ctrl_setup_update(struct omap_dss_device *dssdev, BLIZZARD_SRC_WRITE_LCD : BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE; - omap_rfbi_configure(dssdev, 16, 8); + omapdss_rfbi_set_pixel_size(dssdev, 16); + omapdss_rfbi_set_data_lines(dssdev, 8); + + omap_rfbi_configure(dssdev); blizzard_write(BLIZZARD_INPUT_WIN_X_START_0, tmp, 18); - omap_rfbi_configure(dssdev, 16, 16); + omapdss_rfbi_set_pixel_size(dssdev, 16); + omapdss_rfbi_set_data_lines(dssdev, 16); + + omap_rfbi_configure(dssdev); } static void mipid_transfer(struct spi_device *spi, int cmd, const u8 *wbuf, @@ -297,6 +303,12 @@ static int n8x0_panel_power_on(struct omap_dss_device *dssdev) goto err_plat_en; } + omapdss_rfbi_set_size(dssdev, dssdev->panel.timings.x_res, + dssdev->panel.timings.y_res); + omapdss_rfbi_set_pixel_size(dssdev, dssdev->ctrl.pixel_size); + omapdss_rfbi_set_data_lines(dssdev, dssdev->phy.rfbi.data_lines); + omapdss_rfbi_set_interface_timings(dssdev, &dssdev->ctrl.rfbi_timings); + r = omapdss_rfbi_display_enable(dssdev); if (r) goto err_rfbi_en; @@ -477,6 +489,7 @@ static int n8x0_panel_probe(struct omap_dss_device *dssdev) dssdev->panel.timings.y_res = 480; dssdev->ctrl.pixel_size = 16; dssdev->ctrl.rfbi_timings = n8x0_panel_timings; + dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; memset(&props, 0, sizeof(props)); props.max_brightness = 127; @@ -625,17 +638,25 @@ static int n8x0_panel_update(struct omap_dss_device *dssdev, u16 x, u16 y, u16 w, u16 h) { struct panel_drv_data *ddata = get_drv_data(dssdev); + u16 dw, dh; dev_dbg(&dssdev->dev, "update\n"); + dw = dssdev->panel.timings.x_res; + dh = dssdev->panel.timings.y_res; + + if (x != 0 || y != 0 || w != dw || h != dh) { + dev_err(&dssdev->dev, "invaid update region %d, %d, %d, %d\n", + x, y, w, h); + return -EINVAL; + } + mutex_lock(&ddata->lock); rfbi_bus_lock(); - omap_rfbi_prepare_update(dssdev, &x, &y, &w, &h); - blizzard_ctrl_setup_update(dssdev, x, y, w, h); - omap_rfbi_update(dssdev, x, y, w, h, update_done, NULL); + omap_rfbi_update(dssdev, update_done, NULL); mutex_unlock(&ddata->lock); diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c index b122b0f31c43..908fd268f3dc 100644 --- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c +++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c @@ -175,6 +175,9 @@ static int nec_8048_panel_power_on(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) goto err0; diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c index 2d35bd388860..9df87640ddd2 100644 --- a/drivers/video/omap2/displays/panel-picodlp.c +++ b/drivers/video/omap2/displays/panel-picodlp.c @@ -377,6 +377,10 @@ static int picodlp_panel_power_on(struct omap_dss_device *dssdev) * then only i2c commands can be successfully sent to dpp2600 */ msleep(1000); + + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) { dev_err(&dssdev->dev, "failed to enable DPI\n"); diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c index bd86ba9ccf76..1ec3b277ff15 100644 --- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c @@ -142,6 +142,9 @@ static int sharp_ls_power_on(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) goto err0; diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 6b5e6e0e202f..f2f644680ca8 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -121,6 +121,18 @@ struct taal_data { struct omap_dss_device *dssdev; + /* panel specific HW info */ + struct panel_config *panel_config; + + /* panel HW configuration from DT or platform data */ + int reset_gpio; + int ext_te_gpio; + + bool use_dsi_backlight; + + struct omap_dsi_pin_config pin_config; + + /* runtime variables */ bool enabled; u8 rotate; bool mirror; @@ -145,16 +157,8 @@ struct taal_data { bool ulps_enabled; unsigned ulps_timeout; struct delayed_work ulps_work; - - struct panel_config *panel_config; }; -static inline struct nokia_dsi_panel_data -*get_panel_data(const struct omap_dss_device *dssdev) -{ - return (struct nokia_dsi_panel_data *) dssdev->data; -} - static void taal_esd_work(struct work_struct *work); static void taal_ulps_work(struct work_struct *work); @@ -371,7 +375,6 @@ static void taal_cancel_ulps_work(struct omap_dss_device *dssdev) static int taal_enter_ulps(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; if (td->ulps_enabled) @@ -383,7 +386,8 @@ static int taal_enter_ulps(struct omap_dss_device *dssdev) if (r) goto err; - disable_irq(gpio_to_irq(panel_data->ext_te_gpio)); + if (gpio_is_valid(td->ext_te_gpio)) + disable_irq(gpio_to_irq(td->ext_te_gpio)); omapdss_dsi_display_disable(dssdev, false, true); @@ -405,7 +409,6 @@ err: static int taal_exit_ulps(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; if (!td->ulps_enabled) @@ -425,7 +428,8 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev) goto err2; } - enable_irq(gpio_to_irq(panel_data->ext_te_gpio)); + if (gpio_is_valid(td->ext_te_gpio)) + enable_irq(gpio_to_irq(td->ext_te_gpio)); taal_queue_ulps_work(dssdev); @@ -438,7 +442,8 @@ err2: r = taal_panel_reset(dssdev); if (!r) { - enable_irq(gpio_to_irq(panel_data->ext_te_gpio)); + if (gpio_is_valid(td->ext_te_gpio)) + enable_irq(gpio_to_irq(td->ext_te_gpio)); td->ulps_enabled = false; } err1: @@ -835,94 +840,135 @@ static struct attribute_group taal_attr_group = { static void taal_hw_reset(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); - if (panel_data->reset_gpio == -1) + if (!gpio_is_valid(td->reset_gpio)) return; - gpio_set_value(panel_data->reset_gpio, 1); + gpio_set_value(td->reset_gpio, 1); if (td->panel_config->reset_sequence.high) udelay(td->panel_config->reset_sequence.high); /* reset the panel */ - gpio_set_value(panel_data->reset_gpio, 0); + gpio_set_value(td->reset_gpio, 0); /* assert reset */ if (td->panel_config->reset_sequence.low) udelay(td->panel_config->reset_sequence.low); - gpio_set_value(panel_data->reset_gpio, 1); + gpio_set_value(td->reset_gpio, 1); /* wait after releasing reset */ if (td->panel_config->sleep.hw_reset) msleep(td->panel_config->sleep.hw_reset); } +static void taal_probe_pdata(struct taal_data *td, + const struct nokia_dsi_panel_data *pdata) +{ + td->reset_gpio = pdata->reset_gpio; + + if (pdata->use_ext_te) + td->ext_te_gpio = pdata->ext_te_gpio; + else + td->ext_te_gpio = -1; + + td->esd_interval = pdata->esd_interval; + td->ulps_timeout = pdata->ulps_timeout; + + td->use_dsi_backlight = pdata->use_dsi_backlight; + + td->pin_config = pdata->pin_config; +} + static int taal_probe(struct omap_dss_device *dssdev) { struct backlight_properties props; struct taal_data *td; struct backlight_device *bldev = NULL; - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); - struct panel_config *panel_config = NULL; int r, i; + const char *panel_name; dev_dbg(&dssdev->dev, "probe\n"); - if (!panel_data || !panel_data->name) { - r = -EINVAL; - goto err; + td = devm_kzalloc(&dssdev->dev, sizeof(*td), GFP_KERNEL); + if (!td) + return -ENOMEM; + + dev_set_drvdata(&dssdev->dev, td); + td->dssdev = dssdev; + + if (dssdev->data) { + const struct nokia_dsi_panel_data *pdata = dssdev->data; + + taal_probe_pdata(td, pdata); + + panel_name = pdata->name; + } else { + return -ENODEV; } + if (panel_name == NULL) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(panel_configs); i++) { - if (strcmp(panel_data->name, panel_configs[i].name) == 0) { - panel_config = &panel_configs[i]; + if (strcmp(panel_name, panel_configs[i].name) == 0) { + td->panel_config = &panel_configs[i]; break; } } - if (!panel_config) { - r = -EINVAL; - goto err; - } + if (!td->panel_config) + return -EINVAL; - dssdev->panel.timings = panel_config->timings; + dssdev->panel.timings = td->panel_config->timings; dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888; - - td = kzalloc(sizeof(*td), GFP_KERNEL); - if (!td) { - r = -ENOMEM; - goto err; - } - td->dssdev = dssdev; - td->panel_config = panel_config; - td->esd_interval = panel_data->esd_interval; - td->ulps_enabled = false; - td->ulps_timeout = panel_data->ulps_timeout; + dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | + OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; mutex_init(&td->lock); atomic_set(&td->do_update, 0); - td->workqueue = create_singlethread_workqueue("taal_esd"); - if (td->workqueue == NULL) { - dev_err(&dssdev->dev, "can't create ESD workqueue\n"); - r = -ENOMEM; - goto err_wq; + if (gpio_is_valid(td->reset_gpio)) { + r = devm_gpio_request_one(&dssdev->dev, td->reset_gpio, + GPIOF_OUT_INIT_LOW, "taal rst"); + if (r) { + dev_err(&dssdev->dev, "failed to request reset gpio\n"); + return r; + } } - INIT_DEFERRABLE_WORK(&td->esd_work, taal_esd_work); - INIT_DELAYED_WORK(&td->ulps_work, taal_ulps_work); - dev_set_drvdata(&dssdev->dev, td); + if (gpio_is_valid(td->ext_te_gpio)) { + r = devm_gpio_request_one(&dssdev->dev, td->ext_te_gpio, + GPIOF_IN, "taal irq"); + if (r) { + dev_err(&dssdev->dev, "GPIO request failed\n"); + return r; + } + + r = devm_request_irq(&dssdev->dev, gpio_to_irq(td->ext_te_gpio), + taal_te_isr, + IRQF_TRIGGER_RISING, + "taal vsync", dssdev); - if (gpio_is_valid(panel_data->reset_gpio)) { - r = gpio_request_one(panel_data->reset_gpio, GPIOF_OUT_INIT_LOW, - "taal rst"); if (r) { - dev_err(&dssdev->dev, "failed to request reset gpio\n"); - goto err_rst_gpio; + dev_err(&dssdev->dev, "IRQ request failed\n"); + return r; } + + INIT_DEFERRABLE_WORK(&td->te_timeout_work, + taal_te_timeout_work_callback); + + dev_dbg(&dssdev->dev, "Using GPIO TE\n"); } + td->workqueue = create_singlethread_workqueue("taal_esd"); + if (td->workqueue == NULL) { + dev_err(&dssdev->dev, "can't create ESD workqueue\n"); + return -ENOMEM; + } + INIT_DEFERRABLE_WORK(&td->esd_work, taal_esd_work); + INIT_DELAYED_WORK(&td->ulps_work, taal_ulps_work); + taal_hw_reset(dssdev); - if (panel_data->use_dsi_backlight) { + if (td->use_dsi_backlight) { memset(&props, 0, sizeof(struct backlight_properties)); props.max_brightness = 255; @@ -943,31 +989,6 @@ static int taal_probe(struct omap_dss_device *dssdev) taal_bl_update_status(bldev); } - if (panel_data->use_ext_te) { - int gpio = panel_data->ext_te_gpio; - - r = gpio_request_one(gpio, GPIOF_IN, "taal irq"); - if (r) { - dev_err(&dssdev->dev, "GPIO request failed\n"); - goto err_gpio; - } - - r = request_irq(gpio_to_irq(gpio), taal_te_isr, - IRQF_TRIGGER_RISING, - "taal vsync", dssdev); - - if (r) { - dev_err(&dssdev->dev, "IRQ request failed\n"); - gpio_free(gpio); - goto err_irq; - } - - INIT_DEFERRABLE_WORK(&td->te_timeout_work, - taal_te_timeout_work_callback); - - dev_dbg(&dssdev->dev, "Using GPIO TE\n"); - } - r = omap_dsi_request_vc(dssdev, &td->channel); if (r) { dev_err(&dssdev->dev, "failed to get virtual channel\n"); @@ -991,29 +1012,16 @@ static int taal_probe(struct omap_dss_device *dssdev) err_vc_id: omap_dsi_release_vc(dssdev, td->channel); err_req_vc: - if (panel_data->use_ext_te) - free_irq(gpio_to_irq(panel_data->ext_te_gpio), dssdev); -err_irq: - if (panel_data->use_ext_te) - gpio_free(panel_data->ext_te_gpio); -err_gpio: if (bldev != NULL) backlight_device_unregister(bldev); err_bl: - if (gpio_is_valid(panel_data->reset_gpio)) - gpio_free(panel_data->reset_gpio); -err_rst_gpio: destroy_workqueue(td->workqueue); -err_wq: - kfree(td); -err: return r; } static void __exit taal_remove(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); struct backlight_device *bldev; dev_dbg(&dssdev->dev, "remove\n"); @@ -1021,12 +1029,6 @@ static void __exit taal_remove(struct omap_dss_device *dssdev) sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group); omap_dsi_release_vc(dssdev, td->channel); - if (panel_data->use_ext_te) { - int gpio = panel_data->ext_te_gpio; - free_irq(gpio_to_irq(gpio), dssdev); - gpio_free(gpio); - } - bldev = td->bldev; if (bldev != NULL) { bldev->props.power = FB_BLANK_POWERDOWN; @@ -1040,26 +1042,31 @@ static void __exit taal_remove(struct omap_dss_device *dssdev) /* reset, to be sure that the panel is in a valid state */ taal_hw_reset(dssdev); - - if (gpio_is_valid(panel_data->reset_gpio)) - gpio_free(panel_data->reset_gpio); - - kfree(td); } static int taal_power_on(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); u8 id1, id2, id3; int r; - r = omapdss_dsi_configure_pins(dssdev, &panel_data->pin_config); + r = omapdss_dsi_configure_pins(dssdev, &td->pin_config); if (r) { dev_err(&dssdev->dev, "failed to configure DSI pins\n"); goto err0; }; + omapdss_dsi_set_size(dssdev, dssdev->panel.timings.x_res, + dssdev->panel.timings.y_res); + omapdss_dsi_set_pixel_format(dssdev, OMAP_DSS_DSI_FMT_RGB888); + omapdss_dsi_set_operation_mode(dssdev, OMAP_DSS_DSI_CMD_MODE); + + r = omapdss_dsi_set_clocks(dssdev, 216000000, 10000000); + if (r) { + dev_err(&dssdev->dev, "failed to set HS and LP clocks\n"); + goto err0; + } + r = omapdss_dsi_display_enable(dssdev); if (r) { dev_err(&dssdev->dev, "failed to enable DSI\n"); @@ -1356,7 +1363,6 @@ static int taal_update(struct omap_dss_device *dssdev, u16 x, u16 y, u16 w, u16 h) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h); @@ -1380,7 +1386,7 @@ static int taal_update(struct omap_dss_device *dssdev, if (r) goto err; - if (td->te_enabled && panel_data->use_ext_te) { + if (td->te_enabled && gpio_is_valid(td->ext_te_gpio)) { schedule_delayed_work(&td->te_timeout_work, msecs_to_jiffies(250)); atomic_set(&td->do_update, 1); @@ -1419,7 +1425,6 @@ static int taal_sync(struct omap_dss_device *dssdev) static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; if (enable) @@ -1427,7 +1432,7 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) else r = taal_dcs_write_0(td, MIPI_DCS_SET_TEAR_OFF); - if (!panel_data->use_ext_te) + if (!gpio_is_valid(td->ext_te_gpio)) omapdss_dsi_enable_te(dssdev, enable); if (td->panel_config->sleep.enable_te) @@ -1487,6 +1492,7 @@ static int taal_get_te(struct omap_dss_device *dssdev) static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); + u16 dw, dh; int r; dev_dbg(&dssdev->dev, "rotate %d\n", rotate); @@ -1508,6 +1514,16 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) goto err; } + if (rotate == 0 || rotate == 2) { + dw = dssdev->panel.timings.x_res; + dh = dssdev->panel.timings.y_res; + } else { + dw = dssdev->panel.timings.y_res; + dh = dssdev->panel.timings.x_res; + } + + omapdss_dsi_set_size(dssdev, dw, dh); + td->rotate = rotate; dsi_bus_unlock(dssdev); @@ -1726,7 +1742,6 @@ static void taal_esd_work(struct work_struct *work) struct taal_data *td = container_of(work, struct taal_data, esd_work.work); struct omap_dss_device *dssdev = td->dssdev; - struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); u8 state1, state2; int r; @@ -1773,7 +1788,7 @@ static void taal_esd_work(struct work_struct *work) } /* Self-diagnostics result is also shown on TE GPIO line. We need * to re-enable TE after self diagnostics */ - if (td->te_enabled && panel_data->use_ext_te) { + if (td->te_enabled && gpio_is_valid(td->ext_te_gpio)) { r = taal_dcs_write_1(td, MIPI_DCS_SET_TEAR_ON, 0); if (r) goto err; diff --git a/drivers/video/omap2/displays/panel-tfp410.c b/drivers/video/omap2/displays/panel-tfp410.c index 40cc0cfa5d17..383811cf8648 100644 --- a/drivers/video/omap2/displays/panel-tfp410.c +++ b/drivers/video/omap2/displays/panel-tfp410.c @@ -65,6 +65,9 @@ static int tfp410_power_on(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) goto err0; @@ -116,8 +119,8 @@ static int tfp410_probe(struct omap_dss_device *dssdev) } if (gpio_is_valid(ddata->pd_gpio)) { - r = gpio_request_one(ddata->pd_gpio, GPIOF_OUT_INIT_LOW, - "tfp410 pd"); + r = devm_gpio_request_one(&dssdev->dev, ddata->pd_gpio, + GPIOF_OUT_INIT_LOW, "tfp410 pd"); if (r) { dev_err(&dssdev->dev, "Failed to request PD GPIO %d\n", ddata->pd_gpio); @@ -132,8 +135,7 @@ static int tfp410_probe(struct omap_dss_device *dssdev) if (!adapter) { dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n", i2c_bus_num); - r = -EINVAL; - goto err_i2c; + return -EINVAL; } ddata->i2c_adapter = adapter; @@ -142,10 +144,6 @@ static int tfp410_probe(struct omap_dss_device *dssdev) dev_set_drvdata(&dssdev->dev, ddata); return 0; -err_i2c: - if (gpio_is_valid(ddata->pd_gpio)) - gpio_free(ddata->pd_gpio); - return r; } static void __exit tfp410_remove(struct omap_dss_device *dssdev) @@ -157,9 +155,6 @@ static void __exit tfp410_remove(struct omap_dss_device *dssdev) if (ddata->i2c_adapter) i2c_put_adapter(ddata->i2c_adapter); - if (gpio_is_valid(ddata->pd_gpio)) - gpio_free(ddata->pd_gpio); - dev_set_drvdata(&dssdev->dev, NULL); mutex_unlock(&ddata->lock); @@ -231,7 +226,8 @@ static void tfp410_set_timings(struct omap_dss_device *dssdev, struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); mutex_lock(&ddata->lock); - dpi_set_timings(dssdev, timings); + omapdss_dpi_set_timings(dssdev, timings); + dssdev->panel.timings = *timings; mutex_unlock(&ddata->lock); } diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c index fa7baa650ae0..b5e6dbc59f0a 100644 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c @@ -337,6 +337,9 @@ static int tpo_td043_enable_dss(struct omap_dss_device *dssdev) if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) return 0; + omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); + omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); + r = omapdss_dpi_display_enable(dssdev); if (r) goto err0; @@ -480,7 +483,9 @@ static void tpo_td043_remove(struct omap_dss_device *dssdev) static void tpo_td043_set_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { - dpi_set_timings(dssdev, timings); + omapdss_dpi_set_timings(dssdev, timings); + + dssdev->panel.timings = *timings; } static int tpo_td043_check_timings(struct omap_dss_device *dssdev, diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index b337a8469fd8..80f5390aa136 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -84,7 +84,7 @@ config OMAP2_DSS_SDI config OMAP2_DSS_DSI bool "DSI support" - depends on ARCH_OMAP3 || ARCH_OMAP4 + depends on ARCH_OMAP3 || ARCH_OMAP4 || ARCH_OMAP5 default n help MIPI DSI (Display Serial Interface) support. diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index 5c450b0f94d0..4549869bfe1a 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile @@ -1,9 +1,9 @@ obj-$(CONFIG_OMAP2_DSS) += omapdss.o omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ - manager.o overlay.o apply.o + manager.o manager-sysfs.o overlay.o overlay-sysfs.o output.o apply.o omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o -omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o +omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o venc_panel.o omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \ diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index 0fefc68372b9..19d66f471b4b 100644 --- a/drivers/video/omap2/dss/apply.c +++ b/drivers/video/omap2/dss/apply.c @@ -111,9 +111,6 @@ static struct { struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS]; struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS]; - bool fifo_merge_dirty; - bool fifo_merge; - bool irq_enabled; } dss_data; @@ -424,17 +421,25 @@ static void wait_pending_extra_info_updates(void) int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) { unsigned long timeout = msecs_to_jiffies(500); - struct mgr_priv_data *mp; + struct mgr_priv_data *mp = get_mgr_priv(mgr); u32 irq; + unsigned long flags; int r; int i; - struct omap_dss_device *dssdev = mgr->device; - if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + spin_lock_irqsave(&data_lock, flags); + + if (mgr_manual_update(mgr)) { + spin_unlock_irqrestore(&data_lock, flags); return 0; + } - if (mgr_manual_update(mgr)) + if (!mp->enabled) { + spin_unlock_irqrestore(&data_lock, flags); return 0; + } + + spin_unlock_irqrestore(&data_lock, flags); r = dispc_runtime_get(); if (r) @@ -442,10 +447,8 @@ int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) irq = dispc_mgr_get_vsync_irq(mgr->id); - mp = get_mgr_priv(mgr); i = 0; while (1) { - unsigned long flags; bool shadow_dirty, dirty; spin_lock_irqsave(&data_lock, flags); @@ -489,21 +492,30 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) { unsigned long timeout = msecs_to_jiffies(500); struct ovl_priv_data *op; - struct omap_dss_device *dssdev; + struct mgr_priv_data *mp; u32 irq; + unsigned long flags; int r; int i; if (!ovl->manager) return 0; - dssdev = ovl->manager->device; + mp = get_mgr_priv(ovl->manager); + + spin_lock_irqsave(&data_lock, flags); - if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + if (ovl_manual_update(ovl)) { + spin_unlock_irqrestore(&data_lock, flags); return 0; + } - if (ovl_manual_update(ovl)) + if (!mp->enabled) { + spin_unlock_irqrestore(&data_lock, flags); return 0; + } + + spin_unlock_irqrestore(&data_lock, flags); r = dispc_runtime_get(); if (r) @@ -514,7 +526,6 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) op = get_ovl_priv(ovl); i = 0; while (1) { - unsigned long flags; bool shadow_dirty, dirty; spin_lock_irqsave(&data_lock, flags); @@ -573,7 +584,7 @@ static void dss_ovl_write_regs(struct omap_overlay *ovl) replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode); - r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings); + r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false); if (r) { /* * We can't do much here, as this function can be called from @@ -677,40 +688,11 @@ static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr) mp->shadow_extra_info_dirty = true; } -static void dss_write_regs_common(void) -{ - const int num_mgrs = omap_dss_get_num_overlay_managers(); - int i; - - if (!dss_data.fifo_merge_dirty) - return; - - for (i = 0; i < num_mgrs; ++i) { - struct omap_overlay_manager *mgr; - struct mgr_priv_data *mp; - - mgr = omap_dss_get_overlay_manager(i); - mp = get_mgr_priv(mgr); - - if (mp->enabled) { - if (dss_data.fifo_merge_dirty) { - dispc_enable_fifomerge(dss_data.fifo_merge); - dss_data.fifo_merge_dirty = false; - } - - if (mp->updating) - mp->shadow_info_dirty = true; - } - } -} - static void dss_write_regs(void) { const int num_mgrs = omap_dss_get_num_overlay_managers(); int i; - dss_write_regs_common(); - for (i = 0; i < num_mgrs; ++i) { struct omap_overlay_manager *mgr; struct mgr_priv_data *mp; @@ -799,8 +781,6 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr) dss_mgr_write_regs(mgr); dss_mgr_write_regs_extra(mgr); - dss_write_regs_common(); - mp->updating = true; if (!dss_data.irq_enabled && need_isr()) @@ -984,20 +964,11 @@ static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl, op->extra_info_dirty = true; } -static void dss_apply_fifo_merge(bool use_fifo_merge) -{ - if (dss_data.fifo_merge == use_fifo_merge) - return; - - dss_data.fifo_merge = use_fifo_merge; - dss_data.fifo_merge_dirty = true; -} - -static void dss_ovl_setup_fifo(struct omap_overlay *ovl, - bool use_fifo_merge) +static void dss_ovl_setup_fifo(struct omap_overlay *ovl) { struct ovl_priv_data *op = get_ovl_priv(ovl); u32 fifo_low, fifo_high; + bool use_fifo_merge = false; if (!op->enabled && !op->enabling) return; @@ -1008,8 +979,7 @@ static void dss_ovl_setup_fifo(struct omap_overlay *ovl, dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high); } -static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr, - bool use_fifo_merge) +static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr) { struct omap_overlay *ovl; struct mgr_priv_data *mp; @@ -1020,94 +990,19 @@ static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr, return; list_for_each_entry(ovl, &mgr->overlays, list) - dss_ovl_setup_fifo(ovl, use_fifo_merge); -} - -static void dss_setup_fifos(bool use_fifo_merge) -{ - const int num_mgrs = omap_dss_get_num_overlay_managers(); - struct omap_overlay_manager *mgr; - int i; - - for (i = 0; i < num_mgrs; ++i) { - mgr = omap_dss_get_overlay_manager(i); - dss_mgr_setup_fifos(mgr, use_fifo_merge); - } + dss_ovl_setup_fifo(ovl); } -static int get_num_used_managers(void) +static void dss_setup_fifos(void) { const int num_mgrs = omap_dss_get_num_overlay_managers(); struct omap_overlay_manager *mgr; - struct mgr_priv_data *mp; int i; - int enabled_mgrs; - - enabled_mgrs = 0; for (i = 0; i < num_mgrs; ++i) { mgr = omap_dss_get_overlay_manager(i); - mp = get_mgr_priv(mgr); - - if (!mp->enabled) - continue; - - enabled_mgrs++; + dss_mgr_setup_fifos(mgr); } - - return enabled_mgrs; -} - -static int get_num_used_overlays(void) -{ - const int num_ovls = omap_dss_get_num_overlays(); - struct omap_overlay *ovl; - struct ovl_priv_data *op; - struct mgr_priv_data *mp; - int i; - int enabled_ovls; - - enabled_ovls = 0; - - for (i = 0; i < num_ovls; ++i) { - ovl = omap_dss_get_overlay(i); - op = get_ovl_priv(ovl); - - if (!op->enabled && !op->enabling) - continue; - - mp = get_mgr_priv(ovl->manager); - - if (!mp->enabled) - continue; - - enabled_ovls++; - } - - return enabled_ovls; -} - -static bool get_use_fifo_merge(void) -{ - int enabled_mgrs = get_num_used_managers(); - int enabled_ovls = get_num_used_overlays(); - - if (!dss_has_feature(FEAT_FIFO_MERGE)) - return false; - - /* - * In theory the only requirement for fifomerge is enabled_ovls <= 1. - * However, if we have two managers enabled and set/unset the fifomerge, - * we need to set the GO bits in particular sequence for the managers, - * and wait in between. - * - * This is rather difficult as new apply calls can happen at any time, - * so we simplify the problem by requiring also that enabled_mgrs <= 1. - * In practice this shouldn't matter, because when only one overlay is - * enabled, most likely only one output is enabled. - */ - - return enabled_mgrs <= 1 && enabled_ovls <= 1; } int dss_mgr_enable(struct omap_overlay_manager *mgr) @@ -1115,7 +1010,6 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr) struct mgr_priv_data *mp = get_mgr_priv(mgr); unsigned long flags; int r; - bool fifo_merge; mutex_lock(&apply_lock); @@ -1133,23 +1027,11 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr) goto err; } - /* step 1: setup fifos/fifomerge before enabling the manager */ - - fifo_merge = get_use_fifo_merge(); - dss_setup_fifos(fifo_merge); - dss_apply_fifo_merge(fifo_merge); + dss_setup_fifos(); dss_write_regs(); dss_set_go_bits(); - spin_unlock_irqrestore(&data_lock, flags); - - /* wait until fifo config is in */ - wait_pending_extra_info_updates(); - - /* step 2: enable the manager */ - spin_lock_irqsave(&data_lock, flags); - if (!mgr_manual_update(mgr)) mp->updating = true; @@ -1174,7 +1056,6 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr) { struct mgr_priv_data *mp = get_mgr_priv(mgr); unsigned long flags; - bool fifo_merge; mutex_lock(&apply_lock); @@ -1189,16 +1070,8 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr) mp->updating = false; mp->enabled = false; - fifo_merge = get_use_fifo_merge(); - dss_setup_fifos(fifo_merge); - dss_apply_fifo_merge(fifo_merge); - - dss_write_regs(); - dss_set_go_bits(); - spin_unlock_irqrestore(&data_lock, flags); - wait_pending_extra_info_updates(); out: mutex_unlock(&apply_lock); } @@ -1237,29 +1110,29 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr, spin_unlock_irqrestore(&data_lock, flags); } -int dss_mgr_set_device(struct omap_overlay_manager *mgr, - struct omap_dss_device *dssdev) +int dss_mgr_set_output(struct omap_overlay_manager *mgr, + struct omap_dss_output *output) { int r; mutex_lock(&apply_lock); - if (dssdev->manager) { - DSSERR("display '%s' already has a manager '%s'\n", - dssdev->name, dssdev->manager->name); + if (mgr->output) { + DSSERR("manager %s is already connected to an output\n", + mgr->name); r = -EINVAL; goto err; } - if ((mgr->supported_displays & dssdev->type) == 0) { - DSSERR("display '%s' does not support manager '%s'\n", - dssdev->name, mgr->name); + if ((mgr->supported_outputs & output->id) == 0) { + DSSERR("output does not support manager %s\n", + mgr->name); r = -EINVAL; goto err; } - dssdev->manager = mgr; - mgr->device = dssdev; + output->manager = mgr; + mgr->output = output; mutex_unlock(&apply_lock); @@ -1269,40 +1142,46 @@ err: return r; } -int dss_mgr_unset_device(struct omap_overlay_manager *mgr) +int dss_mgr_unset_output(struct omap_overlay_manager *mgr) { int r; + struct mgr_priv_data *mp = get_mgr_priv(mgr); + unsigned long flags; mutex_lock(&apply_lock); - if (!mgr->device) { - DSSERR("failed to unset display, display not set.\n"); + if (!mgr->output) { + DSSERR("failed to unset output, output not set\n"); r = -EINVAL; goto err; } - /* - * Don't allow currently enabled displays to have the overlay manager - * pulled out from underneath them - */ - if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) { + spin_lock_irqsave(&data_lock, flags); + + if (mp->enabled) { + DSSERR("output can't be unset when manager is enabled\n"); r = -EINVAL; - goto err; + goto err1; } - mgr->device->manager = NULL; - mgr->device = NULL; + spin_unlock_irqrestore(&data_lock, flags); + + mgr->output->manager = NULL; + mgr->output = NULL; mutex_unlock(&apply_lock); return 0; +err1: + spin_unlock_irqrestore(&data_lock, flags); err: mutex_unlock(&apply_lock); + return r; } static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr, - struct omap_video_timings *timings) + const struct omap_video_timings *timings) { struct mgr_priv_data *mp = get_mgr_priv(mgr); @@ -1311,24 +1190,22 @@ static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr, } void dss_mgr_set_timings(struct omap_overlay_manager *mgr, - struct omap_video_timings *timings) + const struct omap_video_timings *timings) { unsigned long flags; - - mutex_lock(&apply_lock); + struct mgr_priv_data *mp = get_mgr_priv(mgr); spin_lock_irqsave(&data_lock, flags); - dss_apply_mgr_timings(mgr, timings); - - dss_write_regs(); - dss_set_go_bits(); + if (mp->updating) { + DSSERR("cannot set timings for %s: manager needs to be disabled\n", + mgr->name); + goto out; + } + dss_apply_mgr_timings(mgr, timings); +out: spin_unlock_irqrestore(&data_lock, flags); - - wait_pending_extra_info_updates(); - - mutex_unlock(&apply_lock); } static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr, @@ -1346,7 +1223,7 @@ void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, unsigned long flags; struct mgr_priv_data *mp = get_mgr_priv(mgr); - mutex_lock(&apply_lock); + spin_lock_irqsave(&data_lock, flags); if (mp->enabled) { DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n", @@ -1354,19 +1231,9 @@ void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, goto out; } - spin_lock_irqsave(&data_lock, flags); - dss_apply_mgr_lcd_config(mgr, config); - - dss_write_regs(); - dss_set_go_bits(); - - spin_unlock_irqrestore(&data_lock, flags); - - wait_pending_extra_info_updates(); - out: - mutex_unlock(&apply_lock); + spin_unlock_irqrestore(&data_lock, flags); } int dss_ovl_set_info(struct omap_overlay *ovl, @@ -1483,6 +1350,13 @@ int dss_ovl_unset_manager(struct omap_overlay *ovl) goto err; } + spin_unlock_irqrestore(&data_lock, flags); + + /* wait for pending extra_info updates to ensure the ovl is disabled */ + wait_pending_extra_info_updates(); + + spin_lock_irqsave(&data_lock, flags); + op->channel = -1; ovl->manager = NULL; @@ -1517,7 +1391,6 @@ int dss_ovl_enable(struct omap_overlay *ovl) { struct ovl_priv_data *op = get_ovl_priv(ovl); unsigned long flags; - bool fifo_merge; int r; mutex_lock(&apply_lock); @@ -1527,7 +1400,7 @@ int dss_ovl_enable(struct omap_overlay *ovl) goto err1; } - if (ovl->manager == NULL || ovl->manager->device == NULL) { + if (ovl->manager == NULL || ovl->manager->output == NULL) { r = -EINVAL; goto err1; } @@ -1543,22 +1416,7 @@ int dss_ovl_enable(struct omap_overlay *ovl) goto err2; } - /* step 1: configure fifos/fifomerge for currently enabled ovls */ - - fifo_merge = get_use_fifo_merge(); - dss_setup_fifos(fifo_merge); - dss_apply_fifo_merge(fifo_merge); - - dss_write_regs(); - dss_set_go_bits(); - - spin_unlock_irqrestore(&data_lock, flags); - - /* wait for fifo configs to go in */ - wait_pending_extra_info_updates(); - - /* step 2: enable the overlay */ - spin_lock_irqsave(&data_lock, flags); + dss_setup_fifos(); op->enabling = false; dss_apply_ovl_enable(ovl, true); @@ -1568,9 +1426,6 @@ int dss_ovl_enable(struct omap_overlay *ovl) spin_unlock_irqrestore(&data_lock, flags); - /* wait for overlay to be enabled */ - wait_pending_extra_info_updates(); - mutex_unlock(&apply_lock); return 0; @@ -1586,7 +1441,6 @@ int dss_ovl_disable(struct omap_overlay *ovl) { struct ovl_priv_data *op = get_ovl_priv(ovl); unsigned long flags; - bool fifo_merge; int r; mutex_lock(&apply_lock); @@ -1596,39 +1450,19 @@ int dss_ovl_disable(struct omap_overlay *ovl) goto err; } - if (ovl->manager == NULL || ovl->manager->device == NULL) { + if (ovl->manager == NULL || ovl->manager->output == NULL) { r = -EINVAL; goto err; } - /* step 1: disable the overlay */ spin_lock_irqsave(&data_lock, flags); dss_apply_ovl_enable(ovl, false); - dss_write_regs(); dss_set_go_bits(); spin_unlock_irqrestore(&data_lock, flags); - /* wait for the overlay to be disabled */ - wait_pending_extra_info_updates(); - - /* step 2: configure fifos/fifomerge */ - spin_lock_irqsave(&data_lock, flags); - - fifo_merge = get_use_fifo_merge(); - dss_setup_fifos(fifo_merge); - dss_apply_fifo_merge(fifo_merge); - - dss_write_regs(); - dss_set_go_bits(); - - spin_unlock_irqrestore(&data_lock, flags); - - /* wait for fifo config to go in */ - wait_pending_extra_info_updates(); - mutex_unlock(&apply_lock); return 0; diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 58bd9c27369d..b2af72dc20bd 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -33,6 +33,7 @@ #include <linux/device.h> #include <linux/regulator/consumer.h> #include <linux/suspend.h> +#include <linux/slab.h> #include <video/omapdss.h> @@ -57,6 +58,11 @@ bool dss_debug; module_param_named(debug, dss_debug, bool, 0644); #endif +const char *dss_get_default_display_name(void) +{ + return core.default_display_name; +} + /* REGULATORS */ struct regulator *dss_get_vdds_dsi(void) @@ -347,17 +353,14 @@ static int dss_driver_probe(struct device *dev) int r; struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver); struct omap_dss_device *dssdev = to_dss_device(dev); - bool force; DSSDBG("driver_probe: dev %s/%s, drv %s\n", dev_name(dev), dssdev->driver_name, dssdrv->driver.name); - dss_init_device(core.pdev, dssdev); - - force = core.default_display_name && - strcmp(core.default_display_name, dssdev->name) == 0; - dss_recheck_connections(dssdev, force); + r = dss_init_device(core.pdev, dssdev); + if (r) + return r; r = dssdrv->probe(dssdev); @@ -416,54 +419,44 @@ void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver) EXPORT_SYMBOL(omap_dss_unregister_driver); /* DEVICE */ -static void reset_device(struct device *dev, int check) -{ - u8 *dev_p = (u8 *)dev; - u8 *dev_end = dev_p + sizeof(*dev); - void *saved_pdata; - - saved_pdata = dev->platform_data; - if (check) { - /* - * Check if there is any other setting than platform_data - * in struct device; warn that these will be reset by our - * init. - */ - dev->platform_data = NULL; - while (dev_p < dev_end) { - if (*dev_p) { - WARN("%s: struct device fields will be " - "discarded\n", - __func__); - break; - } - dev_p++; - } - } - memset(dev, 0, sizeof(*dev)); - dev->platform_data = saved_pdata; -} - static void omap_dss_dev_release(struct device *dev) { - reset_device(dev, 0); + struct omap_dss_device *dssdev = to_dss_device(dev); + kfree(dssdev); } -int omap_dss_register_device(struct omap_dss_device *dssdev, - struct device *parent, int disp_num) +static int disp_num_counter; + +struct omap_dss_device *dss_alloc_and_init_device(struct device *parent) { - WARN_ON(!dssdev->driver_name); + struct omap_dss_device *dssdev; + + dssdev = kzalloc(sizeof(*dssdev), GFP_KERNEL); + if (!dssdev) + return NULL; - reset_device(&dssdev->dev, 1); dssdev->dev.bus = &dss_bus_type; dssdev->dev.parent = parent; dssdev->dev.release = omap_dss_dev_release; - dev_set_name(&dssdev->dev, "display%d", disp_num); - return device_register(&dssdev->dev); + dev_set_name(&dssdev->dev, "display%d", disp_num_counter++); + + device_initialize(&dssdev->dev); + + return dssdev; +} + +int dss_add_device(struct omap_dss_device *dssdev) +{ + return device_add(&dssdev->dev); +} + +void dss_put_device(struct omap_dss_device *dssdev) +{ + put_device(&dssdev->dev); } -void omap_dss_unregister_device(struct omap_dss_device *dssdev) +void dss_unregister_device(struct omap_dss_device *dssdev) { device_unregister(&dssdev->dev); } @@ -471,15 +464,25 @@ void omap_dss_unregister_device(struct omap_dss_device *dssdev) static int dss_unregister_dss_dev(struct device *dev, void *data) { struct omap_dss_device *dssdev = to_dss_device(dev); - omap_dss_unregister_device(dssdev); + dss_unregister_device(dssdev); return 0; } -void omap_dss_unregister_child_devices(struct device *parent) +void dss_unregister_child_devices(struct device *parent) { device_for_each_child(parent, NULL, dss_unregister_dss_dev); } +void dss_copy_device_pdata(struct omap_dss_device *dst, + const struct omap_dss_device *src) +{ + u8 *d = (u8 *)dst; + u8 *s = (u8 *)src; + size_t dsize = sizeof(struct device); + + memcpy(d + dsize, s + dsize, sizeof(struct omap_dss_device) - dsize); +} + /* BUS */ static int __init omap_dss_bus_register(void) { diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index ee9e29639dcc..b43477a5fae8 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -38,7 +38,6 @@ #include <linux/pm_runtime.h> #include <plat/cpu.h> -#include <plat/clock.h> #include <video/omapdss.h> @@ -82,6 +81,30 @@ struct dispc_irq_stats { unsigned irqs[32]; }; +struct dispc_features { + u8 sw_start; + u8 fp_start; + u8 bp_start; + u16 sw_max; + u16 vp_max; + u16 hp_max; + int (*calc_scaling) (enum omap_plane plane, + const struct omap_video_timings *mgr_timings, + u16 width, u16 height, u16 out_width, u16 out_height, + enum omap_color_mode color_mode, bool *five_taps, + int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, + u16 pos_x, unsigned long *core_clk, bool mem_to_mem); + unsigned long (*calc_core_clk) (enum omap_plane plane, + u16 width, u16 height, u16 out_width, u16 out_height, + bool mem_to_mem); + u8 num_fifos; + + /* swap GFX & WB fifos */ + bool gfx_fifo_workaround:1; +}; + +#define DISPC_MAX_NR_FIFOS 5 + static struct { struct platform_device *pdev; void __iomem *base; @@ -91,7 +114,9 @@ static struct { int irq; struct clk *dss_clk; - u32 fifo_size[MAX_DSS_OVERLAYS]; + u32 fifo_size[DISPC_MAX_NR_FIFOS]; + /* maps which plane is using a fifo. fifo-id -> plane-id */ + int fifo_assignment[DISPC_MAX_NR_FIFOS]; spinlock_t irq_lock; u32 irq_error_mask; @@ -102,6 +127,8 @@ static struct { bool ctx_valid; u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; + const struct dispc_features *feat; + #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS spinlock_t irq_stats_lock; struct dispc_irq_stats irq_stats; @@ -211,7 +238,14 @@ static const struct { }, }; +struct color_conv_coef { + int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; + int full_range; +}; + static void _omap_dispc_set_irqs(void); +static unsigned long dispc_plane_pclk_rate(enum omap_plane plane); +static unsigned long dispc_plane_lclk_rate(enum omap_plane plane); static inline void dispc_write_reg(const u16 idx, u32 val) { @@ -509,6 +543,11 @@ u32 dispc_mgr_get_framedone_irq(enum omap_channel channel) return mgr_desc[channel].framedone_irq; } +u32 dispc_wb_get_framedone_irq(void) +{ + return DISPC_IRQ_FRAMEDONEWB; +} + bool dispc_mgr_go_busy(enum omap_channel channel) { return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1; @@ -536,6 +575,30 @@ void dispc_mgr_go(enum omap_channel channel) mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1); } +bool dispc_wb_go_busy(void) +{ + return REG_GET(DISPC_CONTROL2, 6, 6) == 1; +} + +void dispc_wb_go(void) +{ + enum omap_plane plane = OMAP_DSS_WB; + bool enable, go; + + enable = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1; + + if (!enable) + return; + + go = REG_GET(DISPC_CONTROL2, 6, 6) == 1; + if (go) { + DSSERR("GO bit not down for WB\n"); + return; + } + + REG_FLD_MOD(DISPC_CONTROL2, 1, 6, 6); +} + static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value) { dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value); @@ -618,41 +681,41 @@ static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc, } } -static void _dispc_setup_color_conv_coef(void) -{ - int i; - const struct color_conv_coef { - int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; - int full_range; - } ctbl_bt601_5 = { - 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, - }; - - const struct color_conv_coef *ct; +static void dispc_ovl_write_color_conv_coef(enum omap_plane plane, + const struct color_conv_coef *ct) +{ #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) - ct = &ctbl_bt601_5; + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry)); + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb)); + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr)); + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by)); + dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb)); - for (i = 1; i < dss_feat_get_num_ovls(); i++) { - dispc_write_reg(DISPC_OVL_CONV_COEF(i, 0), - CVAL(ct->rcr, ct->ry)); - dispc_write_reg(DISPC_OVL_CONV_COEF(i, 1), - CVAL(ct->gy, ct->rcb)); - dispc_write_reg(DISPC_OVL_CONV_COEF(i, 2), - CVAL(ct->gcb, ct->gcr)); - dispc_write_reg(DISPC_OVL_CONV_COEF(i, 3), - CVAL(ct->bcr, ct->by)); - dispc_write_reg(DISPC_OVL_CONV_COEF(i, 4), - CVAL(0, ct->bcb)); - - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), ct->full_range, - 11, 11); - } + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11); #undef CVAL } +static void dispc_setup_color_conv_coef(void) +{ + int i; + int num_ovl = dss_feat_get_num_ovls(); + int num_wb = dss_feat_get_num_wbs(); + const struct color_conv_coef ctbl_bt601_5_ovl = { + 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, + }; + const struct color_conv_coef ctbl_bt601_5_wb = { + 66, 112, -38, 129, -94, -74, 25, -18, 112, 0, + }; + + for (i = 1; i < num_ovl; i++) + dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_ovl); + + for (; i < num_wb; i++) + dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_wb); +} static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr) { @@ -674,24 +737,32 @@ static void dispc_ovl_set_ba1_uv(enum omap_plane plane, u32 paddr) dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr); } -static void dispc_ovl_set_pos(enum omap_plane plane, int x, int y) +static void dispc_ovl_set_pos(enum omap_plane plane, + enum omap_overlay_caps caps, int x, int y) { - u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0); + u32 val; + + if ((caps & OMAP_DSS_OVL_CAP_POS) == 0) + return; + + val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0); dispc_write_reg(DISPC_OVL_POSITION(plane), val); } -static void dispc_ovl_set_pic_size(enum omap_plane plane, int width, int height) +static void dispc_ovl_set_input_size(enum omap_plane plane, int width, + int height) { u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); - if (plane == OMAP_DSS_GFX) + if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB) dispc_write_reg(DISPC_OVL_SIZE(plane), val); else dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); } -static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height) +static void dispc_ovl_set_output_size(enum omap_plane plane, int width, + int height) { u32 val; @@ -699,14 +770,16 @@ static void dispc_ovl_set_vid_size(enum omap_plane plane, int width, int height) val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); - dispc_write_reg(DISPC_OVL_SIZE(plane), val); + if (plane == OMAP_DSS_WB) + dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); + else + dispc_write_reg(DISPC_OVL_SIZE(plane), val); } -static void dispc_ovl_set_zorder(enum omap_plane plane, u8 zorder) +static void dispc_ovl_set_zorder(enum omap_plane plane, + enum omap_overlay_caps caps, u8 zorder) { - struct omap_overlay *ovl = omap_dss_get_overlay(plane); - - if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) + if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) return; REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26); @@ -723,23 +796,22 @@ static void dispc_ovl_enable_zorder_planes(void) REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25); } -static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, bool enable) +static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, + enum omap_overlay_caps caps, bool enable) { - struct omap_overlay *ovl = omap_dss_get_overlay(plane); - - if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) + if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) return; REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28); } -static void dispc_ovl_setup_global_alpha(enum omap_plane plane, u8 global_alpha) +static void dispc_ovl_setup_global_alpha(enum omap_plane plane, + enum omap_overlay_caps caps, u8 global_alpha) { static const unsigned shifts[] = { 0, 8, 16, 24, }; int shift; - struct omap_overlay *ovl = omap_dss_get_overlay(plane); - if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) + if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) return; shift = shifts[plane]; @@ -947,10 +1019,17 @@ static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane) return channel; } +void dispc_wb_set_channel_in(enum dss_writeback_channel channel) +{ + enum omap_plane plane = OMAP_DSS_WB; + + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16); +} + static void dispc_ovl_set_burst_size(enum omap_plane plane, enum omap_burst_size burst_size) { - static const unsigned shifts[] = { 6, 14, 14, 14, }; + static const unsigned shifts[] = { 6, 14, 14, 14, 14, }; int shift; shift = shifts[plane]; @@ -1027,11 +1106,15 @@ static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable) dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); } -static void dispc_ovl_enable_replication(enum omap_plane plane, bool enable) +static void dispc_ovl_enable_replication(enum omap_plane plane, + enum omap_overlay_caps caps, bool enable) { static const unsigned shifts[] = { 5, 10, 10, 10 }; int shift; + if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0) + return; + shift = shifts[plane]; REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift); } @@ -1045,10 +1128,10 @@ static void dispc_mgr_set_size(enum omap_channel channel, u16 width, dispc_write_reg(DISPC_SIZE_MGR(channel), val); } -static void dispc_read_plane_fifo_sizes(void) +static void dispc_init_fifos(void) { u32 size; - int plane; + int fifo; u8 start, end; u32 unit; @@ -1056,16 +1139,53 @@ static void dispc_read_plane_fifo_sizes(void) dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); - for (plane = 0; plane < dss_feat_get_num_ovls(); ++plane) { - size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(plane), start, end); + for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) { + size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(fifo), start, end); size *= unit; - dispc.fifo_size[plane] = size; + dispc.fifo_size[fifo] = size; + + /* + * By default fifos are mapped directly to overlays, fifo 0 to + * ovl 0, fifo 1 to ovl 1, etc. + */ + dispc.fifo_assignment[fifo] = fifo; + } + + /* + * The GFX fifo on OMAP4 is smaller than the other fifos. The small fifo + * causes problems with certain use cases, like using the tiler in 2D + * mode. The below hack swaps the fifos of GFX and WB planes, thus + * giving GFX plane a larger fifo. WB but should work fine with a + * smaller fifo. + */ + if (dispc.feat->gfx_fifo_workaround) { + u32 v; + + v = dispc_read_reg(DISPC_GLOBAL_BUFFER); + + v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */ + v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */ + v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */ + v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */ + + dispc_write_reg(DISPC_GLOBAL_BUFFER, v); + + dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB; + dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX; } } static u32 dispc_ovl_get_fifo_size(enum omap_plane plane) { - return dispc.fifo_size[plane]; + int fifo; + u32 size = 0; + + for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) { + if (dispc.fifo_assignment[fifo] == plane) + size += dispc.fifo_size[fifo]; + } + + return size; } void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) @@ -1141,6 +1261,14 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) { *fifo_low = ovl_fifo_size - burst_size * 2; *fifo_high = total_fifo_size - burst_size; + } else if (plane == OMAP_DSS_WB) { + /* + * Most optimal configuration for writeback is to push out data + * to the interconnect the moment writeback pushes enough pixels + * in the FIFO to form a burst + */ + *fifo_low = 0; + *fifo_high = burst_size; } else { *fifo_low = ovl_fifo_size - burst_size; *fifo_high = total_fifo_size - buf_unit; @@ -1383,6 +1511,7 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, { int scale_x = out_width != orig_width; int scale_y = out_height != orig_height; + bool chroma_upscale = plane != OMAP_DSS_WB ? true : false; if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) return; @@ -1390,7 +1519,8 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, color_mode != OMAP_DSS_COLOR_UYVY && color_mode != OMAP_DSS_COLOR_NV12)) { /* reset chroma resampling for RGB formats */ - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8); + if (plane != OMAP_DSS_WB) + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8); return; } @@ -1399,23 +1529,34 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, switch (color_mode) { case OMAP_DSS_COLOR_NV12: - /* UV is subsampled by 2 vertically*/ - orig_height >>= 1; - /* UV is subsampled by 2 horz.*/ - orig_width >>= 1; + if (chroma_upscale) { + /* UV is subsampled by 2 horizontally and vertically */ + orig_height >>= 1; + orig_width >>= 1; + } else { + /* UV is downsampled by 2 horizontally and vertically */ + orig_height <<= 1; + orig_width <<= 1; + } + break; case OMAP_DSS_COLOR_YUV2: case OMAP_DSS_COLOR_UYVY: - /*For YUV422 with 90/270 rotation, - *we don't upsample chroma - */ + /* For YUV422 with 90/270 rotation, we don't upsample chroma */ if (rotation == OMAP_DSS_ROT_0 || - rotation == OMAP_DSS_ROT_180) - /* UV is subsampled by 2 hrz*/ - orig_width >>= 1; + rotation == OMAP_DSS_ROT_180) { + if (chroma_upscale) + /* UV is subsampled by 2 horizontally */ + orig_width >>= 1; + else + /* UV is downsampled by 2 horizontally */ + orig_width <<= 1; + } + /* must use FIR for YUV422 if rotated */ if (rotation != OMAP_DSS_ROT_0) scale_x = scale_y = true; + break; default: BUG(); @@ -1431,8 +1572,10 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, out_width, out_height, five_taps, rotation, DISPC_COLOR_COMPONENT_UV); - REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), - (scale_x || scale_y) ? 1 : 0, 8, 8); + if (plane != OMAP_DSS_WB) + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), + (scale_x || scale_y) ? 1 : 0, 8, 8); + /* set H scaling */ REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5); /* set V scaling */ @@ -1848,22 +1991,19 @@ static void calc_tiler_rotation_offset(u16 screen_width, u16 width, * This function is used to avoid synclosts in OMAP3, because of some * undocumented horizontal position and timing related limitations. */ -static int check_horiz_timing_omap3(enum omap_channel channel, +static int check_horiz_timing_omap3(enum omap_plane plane, const struct omap_video_timings *t, u16 pos_x, u16 width, u16 height, u16 out_width, u16 out_height) { int DS = DIV_ROUND_UP(height, out_height); - unsigned long nonactive, lclk, pclk; + unsigned long nonactive; static const u8 limits[3] = { 8, 10, 20 }; u64 val, blank; + unsigned long pclk = dispc_plane_pclk_rate(plane); + unsigned long lclk = dispc_plane_lclk_rate(plane); int i; nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width; - pclk = dispc_mgr_pclk_rate(channel); - if (dss_mgr_is_lcd(channel)) - lclk = dispc_mgr_lclk_rate(channel); - else - lclk = dispc_fclk_rate(); i = 0; if (out_height < height) @@ -1900,13 +2040,14 @@ static int check_horiz_timing_omap3(enum omap_channel channel, return 0; } -static unsigned long calc_core_clk_five_taps(enum omap_channel channel, +static unsigned long calc_core_clk_five_taps(enum omap_plane plane, const struct omap_video_timings *mgr_timings, u16 width, u16 height, u16 out_width, u16 out_height, enum omap_color_mode color_mode) { u32 core_clk = 0; - u64 tmp, pclk = dispc_mgr_pclk_rate(channel); + u64 tmp; + unsigned long pclk = dispc_plane_pclk_rate(plane); if (height <= out_height && width <= out_width) return (unsigned long) pclk; @@ -1940,11 +2081,22 @@ static unsigned long calc_core_clk_five_taps(enum omap_channel channel, return core_clk; } -static unsigned long calc_core_clk(enum omap_channel channel, u16 width, - u16 height, u16 out_width, u16 out_height) +static unsigned long calc_core_clk_24xx(enum omap_plane plane, u16 width, + u16 height, u16 out_width, u16 out_height, bool mem_to_mem) +{ + unsigned long pclk = dispc_plane_pclk_rate(plane); + + if (height > out_height && width > out_width) + return pclk * 4; + else + return pclk * 2; +} + +static unsigned long calc_core_clk_34xx(enum omap_plane plane, u16 width, + u16 height, u16 out_width, u16 out_height, bool mem_to_mem) { unsigned int hf, vf; - unsigned long pclk = dispc_mgr_pclk_rate(channel); + unsigned long pclk = dispc_plane_pclk_rate(plane); /* * FIXME how to determine the 'A' factor @@ -1959,51 +2111,207 @@ static unsigned long calc_core_clk(enum omap_channel channel, u16 width, hf = 2; else hf = 1; - if (height > out_height) vf = 2; else vf = 1; - if (cpu_is_omap24xx()) { - if (vf > 1 && hf > 1) - return pclk * 4; - else - return pclk * 2; - } else if (cpu_is_omap34xx()) { - return pclk * vf * hf; - } else { - if (hf > 1) - return DIV_ROUND_UP(pclk, out_width) * width; - else - return pclk; + return pclk * vf * hf; +} + +static unsigned long calc_core_clk_44xx(enum omap_plane plane, u16 width, + u16 height, u16 out_width, u16 out_height, bool mem_to_mem) +{ + unsigned long pclk; + + /* + * If the overlay/writeback is in mem to mem mode, there are no + * downscaling limitations with respect to pixel clock, return 1 as + * required core clock to represent that we have sufficient enough + * core clock to do maximum downscaling + */ + if (mem_to_mem) + return 1; + + pclk = dispc_plane_pclk_rate(plane); + + if (width > out_width) + return DIV_ROUND_UP(pclk, out_width) * width; + else + return pclk; +} + +static int dispc_ovl_calc_scaling_24xx(enum omap_plane plane, + const struct omap_video_timings *mgr_timings, + u16 width, u16 height, u16 out_width, u16 out_height, + enum omap_color_mode color_mode, bool *five_taps, + int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, + u16 pos_x, unsigned long *core_clk, bool mem_to_mem) +{ + int error; + u16 in_width, in_height; + int min_factor = min(*decim_x, *decim_y); + const int maxsinglelinewidth = + dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); + + *five_taps = false; + + do { + in_height = DIV_ROUND_UP(height, *decim_y); + in_width = DIV_ROUND_UP(width, *decim_x); + *core_clk = dispc.feat->calc_core_clk(plane, in_width, + in_height, out_width, out_height, mem_to_mem); + error = (in_width > maxsinglelinewidth || !*core_clk || + *core_clk > dispc_core_clk_rate()); + if (error) { + if (*decim_x == *decim_y) { + *decim_x = min_factor; + ++*decim_y; + } else { + swap(*decim_x, *decim_y); + if (*decim_x < *decim_y) + ++*decim_x; + } + } + } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); + + if (in_width > maxsinglelinewidth) { + DSSERR("Cannot scale max input width exceeded"); + return -EINVAL; } + return 0; } -static int dispc_ovl_calc_scaling(enum omap_plane plane, - enum omap_channel channel, +static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane, const struct omap_video_timings *mgr_timings, u16 width, u16 height, u16 out_width, u16 out_height, enum omap_color_mode color_mode, bool *five_taps, - int *x_predecim, int *y_predecim, u16 pos_x) + int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, + u16 pos_x, unsigned long *core_clk, bool mem_to_mem) { - struct omap_overlay *ovl = omap_dss_get_overlay(plane); - const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); + int error; + u16 in_width, in_height; + int min_factor = min(*decim_x, *decim_y); + const int maxsinglelinewidth = + dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); + + do { + in_height = DIV_ROUND_UP(height, *decim_y); + in_width = DIV_ROUND_UP(width, *decim_x); + *core_clk = calc_core_clk_five_taps(plane, mgr_timings, + in_width, in_height, out_width, out_height, color_mode); + + error = check_horiz_timing_omap3(plane, mgr_timings, + pos_x, in_width, in_height, out_width, + out_height); + + if (in_width > maxsinglelinewidth) + if (in_height > out_height && + in_height < out_height * 2) + *five_taps = false; + if (!*five_taps) + *core_clk = dispc.feat->calc_core_clk(plane, in_width, + in_height, out_width, out_height, + mem_to_mem); + + error = (error || in_width > maxsinglelinewidth * 2 || + (in_width > maxsinglelinewidth && *five_taps) || + !*core_clk || *core_clk > dispc_core_clk_rate()); + if (error) { + if (*decim_x == *decim_y) { + *decim_x = min_factor; + ++*decim_y; + } else { + swap(*decim_x, *decim_y); + if (*decim_x < *decim_y) + ++*decim_x; + } + } + } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); + + if (check_horiz_timing_omap3(plane, mgr_timings, pos_x, width, height, + out_width, out_height)){ + DSSERR("horizontal timing too tight\n"); + return -EINVAL; + } + + if (in_width > (maxsinglelinewidth * 2)) { + DSSERR("Cannot setup scaling"); + DSSERR("width exceeds maximum width possible"); + return -EINVAL; + } + + if (in_width > maxsinglelinewidth && *five_taps) { + DSSERR("cannot setup scaling with five taps"); + return -EINVAL; + } + return 0; +} + +static int dispc_ovl_calc_scaling_44xx(enum omap_plane plane, + const struct omap_video_timings *mgr_timings, + u16 width, u16 height, u16 out_width, u16 out_height, + enum omap_color_mode color_mode, bool *five_taps, + int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, + u16 pos_x, unsigned long *core_clk, bool mem_to_mem) +{ + u16 in_width, in_width_max; + int decim_x_min = *decim_x; + u16 in_height = DIV_ROUND_UP(height, *decim_y); const int maxsinglelinewidth = dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); + unsigned long pclk = dispc_plane_pclk_rate(plane); + const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); + + if (mem_to_mem) + in_width_max = DIV_ROUND_UP(out_width, maxdownscale); + else + in_width_max = dispc_core_clk_rate() / + DIV_ROUND_UP(pclk, out_width); + + *decim_x = DIV_ROUND_UP(width, in_width_max); + + *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min; + if (*decim_x > *x_predecim) + return -EINVAL; + + do { + in_width = DIV_ROUND_UP(width, *decim_x); + } while (*decim_x <= *x_predecim && + in_width > maxsinglelinewidth && ++*decim_x); + + if (in_width > maxsinglelinewidth) { + DSSERR("Cannot scale width exceeds max line width"); + return -EINVAL; + } + + *core_clk = dispc.feat->calc_core_clk(plane, in_width, in_height, + out_width, out_height, mem_to_mem); + return 0; +} + +static int dispc_ovl_calc_scaling(enum omap_plane plane, + enum omap_overlay_caps caps, + const struct omap_video_timings *mgr_timings, + u16 width, u16 height, u16 out_width, u16 out_height, + enum omap_color_mode color_mode, bool *five_taps, + int *x_predecim, int *y_predecim, u16 pos_x, + enum omap_dss_rotation_type rotation_type, bool mem_to_mem) +{ + const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); const int max_decim_limit = 16; unsigned long core_clk = 0; - int decim_x, decim_y, error, min_factor; - u16 in_width, in_height, in_width_max = 0; + int decim_x, decim_y, ret; if (width == out_width && height == out_height) return 0; - if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) + if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0) return -EINVAL; *x_predecim = max_decim_limit; - *y_predecim = max_decim_limit; + *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER && + dss_has_feature(FEAT_BURST_2D)) ? 2 : max_decim_limit; if (color_mode == OMAP_DSS_COLOR_CLUT1 || color_mode == OMAP_DSS_COLOR_CLUT2 || @@ -2018,118 +2326,18 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale); decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale); - min_factor = min(decim_x, decim_y); - if (decim_x > *x_predecim || out_width > width * 8) return -EINVAL; if (decim_y > *y_predecim || out_height > height * 8) return -EINVAL; - if (cpu_is_omap24xx()) { - *five_taps = false; - - do { - in_height = DIV_ROUND_UP(height, decim_y); - in_width = DIV_ROUND_UP(width, decim_x); - core_clk = calc_core_clk(channel, in_width, in_height, - out_width, out_height); - error = (in_width > maxsinglelinewidth || !core_clk || - core_clk > dispc_core_clk_rate()); - if (error) { - if (decim_x == decim_y) { - decim_x = min_factor; - decim_y++; - } else { - swap(decim_x, decim_y); - if (decim_x < decim_y) - decim_x++; - } - } - } while (decim_x <= *x_predecim && decim_y <= *y_predecim && - error); - - if (in_width > maxsinglelinewidth) { - DSSERR("Cannot scale max input width exceeded"); - return -EINVAL; - } - } else if (cpu_is_omap34xx()) { - - do { - in_height = DIV_ROUND_UP(height, decim_y); - in_width = DIV_ROUND_UP(width, decim_x); - core_clk = calc_core_clk_five_taps(channel, mgr_timings, - in_width, in_height, out_width, out_height, - color_mode); - - error = check_horiz_timing_omap3(channel, mgr_timings, - pos_x, in_width, in_height, out_width, - out_height); - - if (in_width > maxsinglelinewidth) - if (in_height > out_height && - in_height < out_height * 2) - *five_taps = false; - if (!*five_taps) - core_clk = calc_core_clk(channel, in_width, - in_height, out_width, out_height); - error = (error || in_width > maxsinglelinewidth * 2 || - (in_width > maxsinglelinewidth && *five_taps) || - !core_clk || core_clk > dispc_core_clk_rate()); - if (error) { - if (decim_x == decim_y) { - decim_x = min_factor; - decim_y++; - } else { - swap(decim_x, decim_y); - if (decim_x < decim_y) - decim_x++; - } - } - } while (decim_x <= *x_predecim && decim_y <= *y_predecim - && error); - - if (check_horiz_timing_omap3(channel, mgr_timings, pos_x, width, - height, out_width, out_height)){ - DSSERR("horizontal timing too tight\n"); - return -EINVAL; - } - - if (in_width > (maxsinglelinewidth * 2)) { - DSSERR("Cannot setup scaling"); - DSSERR("width exceeds maximum width possible"); - return -EINVAL; - } - - if (in_width > maxsinglelinewidth && *five_taps) { - DSSERR("cannot setup scaling with five taps"); - return -EINVAL; - } - } else { - int decim_x_min = decim_x; - in_height = DIV_ROUND_UP(height, decim_y); - in_width_max = dispc_core_clk_rate() / - DIV_ROUND_UP(dispc_mgr_pclk_rate(channel), - out_width); - decim_x = DIV_ROUND_UP(width, in_width_max); - - decim_x = decim_x > decim_x_min ? decim_x : decim_x_min; - if (decim_x > *x_predecim) - return -EINVAL; - - do { - in_width = DIV_ROUND_UP(width, decim_x); - } while (decim_x <= *x_predecim && - in_width > maxsinglelinewidth && decim_x++); - - if (in_width > maxsinglelinewidth) { - DSSERR("Cannot scale width exceeds max line width"); - return -EINVAL; - } - - core_clk = calc_core_clk(channel, in_width, in_height, - out_width, out_height); - } + ret = dispc.feat->calc_scaling(plane, mgr_timings, width, height, + out_width, out_height, color_mode, five_taps, + x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk, + mem_to_mem); + if (ret) + return ret; DSSDBG("required core clk rate = %lu Hz\n", core_clk); DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate()); @@ -2147,69 +2355,64 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, return 0; } -int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, - bool replication, const struct omap_video_timings *mgr_timings) +static int dispc_ovl_setup_common(enum omap_plane plane, + enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr, + u16 screen_width, int pos_x, int pos_y, u16 width, u16 height, + u16 out_width, u16 out_height, enum omap_color_mode color_mode, + u8 rotation, bool mirror, u8 zorder, u8 pre_mult_alpha, + u8 global_alpha, enum omap_dss_rotation_type rotation_type, + bool replication, const struct omap_video_timings *mgr_timings, + bool mem_to_mem) { - struct omap_overlay *ovl = omap_dss_get_overlay(plane); bool five_taps = true; bool fieldmode = 0; int r, cconv = 0; unsigned offset0, offset1; s32 row_inc; s32 pix_inc; - u16 frame_height = oi->height; + u16 frame_height = height; unsigned int field_offset = 0; - u16 in_height = oi->height; - u16 in_width = oi->width; - u16 out_width, out_height; - enum omap_channel channel; + u16 in_height = height; + u16 in_width = width; int x_predecim = 1, y_predecim = 1; bool ilace = mgr_timings->interlace; - channel = dispc_ovl_get_channel_out(plane); - - DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " - "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d\n", - plane, oi->paddr, oi->p_uv_addr, - oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, - oi->out_width, oi->out_height, oi->color_mode, oi->rotation, - oi->mirror, ilace, channel, replication); - - if (oi->paddr == 0) + if (paddr == 0) return -EINVAL; - out_width = oi->out_width == 0 ? oi->width : oi->out_width; - out_height = oi->out_height == 0 ? oi->height : oi->out_height; + out_width = out_width == 0 ? width : out_width; + out_height = out_height == 0 ? height : out_height; - if (ilace && oi->height == out_height) + if (ilace && height == out_height) fieldmode = 1; if (ilace) { if (fieldmode) in_height /= 2; - oi->pos_y /= 2; + pos_y /= 2; out_height /= 2; DSSDBG("adjusting for ilace: height %d, pos_y %d, " - "out_height %d\n", - in_height, oi->pos_y, out_height); + "out_height %d\n", in_height, pos_y, + out_height); } - if (!dss_feat_color_mode_supported(plane, oi->color_mode)) + if (!dss_feat_color_mode_supported(plane, color_mode)) return -EINVAL; - r = dispc_ovl_calc_scaling(plane, channel, mgr_timings, in_width, - in_height, out_width, out_height, oi->color_mode, - &five_taps, &x_predecim, &y_predecim, oi->pos_x); + r = dispc_ovl_calc_scaling(plane, caps, mgr_timings, in_width, + in_height, out_width, out_height, color_mode, + &five_taps, &x_predecim, &y_predecim, pos_x, + rotation_type, mem_to_mem); if (r) return r; in_width = DIV_ROUND_UP(in_width, x_predecim); in_height = DIV_ROUND_UP(in_height, y_predecim); - if (oi->color_mode == OMAP_DSS_COLOR_YUV2 || - oi->color_mode == OMAP_DSS_COLOR_UYVY || - oi->color_mode == OMAP_DSS_COLOR_NV12) + if (color_mode == OMAP_DSS_COLOR_YUV2 || + color_mode == OMAP_DSS_COLOR_UYVY || + color_mode == OMAP_DSS_COLOR_NV12) cconv = 1; if (ilace && !fieldmode) { @@ -2235,70 +2438,144 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, row_inc = 0; pix_inc = 0; - if (oi->rotation_type == OMAP_DSS_ROT_TILER) - calc_tiler_rotation_offset(oi->screen_width, in_width, - oi->color_mode, fieldmode, field_offset, + if (rotation_type == OMAP_DSS_ROT_TILER) + calc_tiler_rotation_offset(screen_width, in_width, + color_mode, fieldmode, field_offset, &offset0, &offset1, &row_inc, &pix_inc, x_predecim, y_predecim); - else if (oi->rotation_type == OMAP_DSS_ROT_DMA) - calc_dma_rotation_offset(oi->rotation, oi->mirror, - oi->screen_width, in_width, frame_height, - oi->color_mode, fieldmode, field_offset, + else if (rotation_type == OMAP_DSS_ROT_DMA) + calc_dma_rotation_offset(rotation, mirror, + screen_width, in_width, frame_height, + color_mode, fieldmode, field_offset, &offset0, &offset1, &row_inc, &pix_inc, x_predecim, y_predecim); else - calc_vrfb_rotation_offset(oi->rotation, oi->mirror, - oi->screen_width, in_width, frame_height, - oi->color_mode, fieldmode, field_offset, + calc_vrfb_rotation_offset(rotation, mirror, + screen_width, in_width, frame_height, + color_mode, fieldmode, field_offset, &offset0, &offset1, &row_inc, &pix_inc, x_predecim, y_predecim); DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n", offset0, offset1, row_inc, pix_inc); - dispc_ovl_set_color_mode(plane, oi->color_mode); + dispc_ovl_set_color_mode(plane, color_mode); - dispc_ovl_configure_burst_type(plane, oi->rotation_type); + dispc_ovl_configure_burst_type(plane, rotation_type); - dispc_ovl_set_ba0(plane, oi->paddr + offset0); - dispc_ovl_set_ba1(plane, oi->paddr + offset1); + dispc_ovl_set_ba0(plane, paddr + offset0); + dispc_ovl_set_ba1(plane, paddr + offset1); - if (OMAP_DSS_COLOR_NV12 == oi->color_mode) { - dispc_ovl_set_ba0_uv(plane, oi->p_uv_addr + offset0); - dispc_ovl_set_ba1_uv(plane, oi->p_uv_addr + offset1); + if (OMAP_DSS_COLOR_NV12 == color_mode) { + dispc_ovl_set_ba0_uv(plane, p_uv_addr + offset0); + dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1); } - dispc_ovl_set_row_inc(plane, row_inc); dispc_ovl_set_pix_inc(plane, pix_inc); - DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, in_width, + DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width, in_height, out_width, out_height); - dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y); + dispc_ovl_set_pos(plane, caps, pos_x, pos_y); - dispc_ovl_set_pic_size(plane, in_width, in_height); + dispc_ovl_set_input_size(plane, in_width, in_height); - if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) { + if (caps & OMAP_DSS_OVL_CAP_SCALE) { dispc_ovl_set_scaling(plane, in_width, in_height, out_width, out_height, ilace, five_taps, fieldmode, - oi->color_mode, oi->rotation); - dispc_ovl_set_vid_size(plane, out_width, out_height); + color_mode, rotation); + dispc_ovl_set_output_size(plane, out_width, out_height); dispc_ovl_set_vid_color_conv(plane, cconv); } - dispc_ovl_set_rotation_attrs(plane, oi->rotation, oi->mirror, - oi->color_mode); + dispc_ovl_set_rotation_attrs(plane, rotation, mirror, color_mode); - dispc_ovl_set_zorder(plane, oi->zorder); - dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha); - dispc_ovl_setup_global_alpha(plane, oi->global_alpha); + dispc_ovl_set_zorder(plane, caps, zorder); + dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha); + dispc_ovl_setup_global_alpha(plane, caps, global_alpha); - dispc_ovl_enable_replication(plane, replication); + dispc_ovl_enable_replication(plane, caps, replication); return 0; } +int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, + bool replication, const struct omap_video_timings *mgr_timings, + bool mem_to_mem) +{ + int r; + struct omap_overlay *ovl = omap_dss_get_overlay(plane); + enum omap_channel channel; + + channel = dispc_ovl_get_channel_out(plane); + + DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " + "%dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n", + plane, oi->paddr, oi->p_uv_addr, oi->screen_width, oi->pos_x, + oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, + oi->color_mode, oi->rotation, oi->mirror, channel, replication); + + r = dispc_ovl_setup_common(plane, ovl->caps, oi->paddr, oi->p_uv_addr, + oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, + oi->out_width, oi->out_height, oi->color_mode, oi->rotation, + oi->mirror, oi->zorder, oi->pre_mult_alpha, oi->global_alpha, + oi->rotation_type, replication, mgr_timings, mem_to_mem); + + return r; +} + +int dispc_wb_setup(const struct omap_dss_writeback_info *wi, + bool mem_to_mem, const struct omap_video_timings *mgr_timings) +{ + int r; + u32 l; + enum omap_plane plane = OMAP_DSS_WB; + const int pos_x = 0, pos_y = 0; + const u8 zorder = 0, global_alpha = 0; + const bool replication = false; + bool truncation; + int in_width = mgr_timings->x_res; + int in_height = mgr_timings->y_res; + enum omap_overlay_caps caps = + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA; + + DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, " + "rot %d, mir %d\n", wi->paddr, wi->p_uv_addr, in_width, + in_height, wi->width, wi->height, wi->color_mode, wi->rotation, + wi->mirror); + + r = dispc_ovl_setup_common(plane, caps, wi->paddr, wi->p_uv_addr, + wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width, + wi->height, wi->color_mode, wi->rotation, wi->mirror, zorder, + wi->pre_mult_alpha, global_alpha, wi->rotation_type, + replication, mgr_timings, mem_to_mem); + + switch (wi->color_mode) { + case OMAP_DSS_COLOR_RGB16: + case OMAP_DSS_COLOR_RGB24P: + case OMAP_DSS_COLOR_ARGB16: + case OMAP_DSS_COLOR_RGBA16: + case OMAP_DSS_COLOR_RGB12U: + case OMAP_DSS_COLOR_ARGB16_1555: + case OMAP_DSS_COLOR_XRGB16_1555: + case OMAP_DSS_COLOR_RGBX16: + truncation = true; + break; + default: + truncation = false; + break; + } + + /* setup extra DISPC_WB_ATTRIBUTES */ + l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); + l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */ + l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */ + dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l); + + return r; +} + int dispc_ovl_enable(enum omap_plane plane, bool enable) { DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); @@ -2451,6 +2728,47 @@ void dispc_mgr_enable(enum omap_channel channel, bool enable) BUG(); } +void dispc_wb_enable(bool enable) +{ + enum omap_plane plane = OMAP_DSS_WB; + struct completion frame_done_completion; + bool is_on; + int r; + u32 irq; + + is_on = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0); + irq = DISPC_IRQ_FRAMEDONEWB; + + if (!enable && is_on) { + init_completion(&frame_done_completion); + + r = omap_dispc_register_isr(dispc_disable_isr, + &frame_done_completion, irq); + if (r) + DSSERR("failed to register FRAMEDONEWB isr\n"); + } + + REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); + + if (!enable && is_on) { + if (!wait_for_completion_timeout(&frame_done_completion, + msecs_to_jiffies(100))) + DSSERR("timeout waiting for FRAMEDONEWB\n"); + + r = omap_dispc_unregister_isr(dispc_disable_isr, + &frame_done_completion, irq); + if (r) + DSSERR("failed to unregister FRAMEDONEWB isr\n"); + } +} + +bool dispc_wb_is_enabled(void) +{ + enum omap_plane plane = OMAP_DSS_WB; + + return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0); +} + void dispc_lcd_enable_signal_polarity(bool act_high) { if (!dss_has_feature(FEAT_LCDENABLEPOL)) @@ -2605,24 +2923,13 @@ static bool _dispc_mgr_size_ok(u16 width, u16 height) static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, int vsw, int vfp, int vbp) { - if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) { - if (hsw < 1 || hsw > 64 || - hfp < 1 || hfp > 256 || - hbp < 1 || hbp > 256 || - vsw < 1 || vsw > 64 || - vfp < 0 || vfp > 255 || - vbp < 0 || vbp > 255) - return false; - } else { - if (hsw < 1 || hsw > 256 || - hfp < 1 || hfp > 4096 || - hbp < 1 || hbp > 4096 || - vsw < 1 || vsw > 256 || - vfp < 0 || vfp > 4095 || - vbp < 0 || vbp > 4095) - return false; - } - + if (hsw < 1 || hsw > dispc.feat->sw_max || + hfp < 1 || hfp > dispc.feat->hp_max || + hbp < 1 || hbp > dispc.feat->hp_max || + vsw < 1 || vsw > dispc.feat->sw_max || + vfp < 0 || vfp > dispc.feat->vp_max || + vbp < 0 || vbp > dispc.feat->vp_max) + return false; return true; } @@ -2654,19 +2961,12 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, u32 timing_h, timing_v, l; bool onoff, rf, ipc; - if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) { - timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) | - FLD_VAL(hbp-1, 27, 20); - - timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) | - FLD_VAL(vbp, 27, 20); - } else { - timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) | - FLD_VAL(hbp-1, 31, 20); - - timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) | - FLD_VAL(vbp, 31, 20); - } + timing_h = FLD_VAL(hsw-1, dispc.feat->sw_start, 0) | + FLD_VAL(hfp-1, dispc.feat->fp_start, 8) | + FLD_VAL(hbp-1, dispc.feat->bp_start, 20); + timing_v = FLD_VAL(vsw-1, dispc.feat->sw_start, 0) | + FLD_VAL(vfp, dispc.feat->fp_start, 8) | + FLD_VAL(vbp, dispc.feat->bp_start, 20); dispc_write_reg(DISPC_TIMING_H(channel), timing_h); dispc_write_reg(DISPC_TIMING_V(channel), timing_v); @@ -2872,6 +3172,23 @@ unsigned long dispc_core_clk_rate(void) return fclk / lcd; } +static unsigned long dispc_plane_pclk_rate(enum omap_plane plane) +{ + enum omap_channel channel = dispc_ovl_get_channel_out(plane); + + return dispc_mgr_pclk_rate(channel); +} + +static unsigned long dispc_plane_lclk_rate(enum omap_plane plane) +{ + enum omap_channel channel = dispc_ovl_get_channel_out(plane); + + if (dss_mgr_is_lcd(channel)) + return dispc_mgr_lclk_rate(channel); + else + return dispc_fclk_rate(); + +} static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel) { int lcd, pcd; @@ -3492,7 +3809,7 @@ static void dispc_error_worker(struct work_struct *work) ovl->name); dispc_ovl_enable(ovl->id, false); dispc_mgr_go(ovl->manager->id); - mdelay(50); + msleep(50); } } @@ -3504,7 +3821,7 @@ static void dispc_error_worker(struct work_struct *work) bit = mgr_desc[i].sync_lost_irq; if (bit & errors) { - struct omap_dss_device *dssdev = mgr->device; + struct omap_dss_device *dssdev = mgr->get_device(mgr); bool enable; DSSERR("SYNC_LOST on channel %s, restarting the output " @@ -3524,7 +3841,7 @@ static void dispc_error_worker(struct work_struct *work) } dispc_mgr_go(mgr->id); - mdelay(50); + msleep(50); if (enable) dssdev->driver->enable(dssdev); @@ -3535,9 +3852,13 @@ static void dispc_error_worker(struct work_struct *work) DSSERR("OCP_ERR\n"); for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { struct omap_overlay_manager *mgr; + struct omap_dss_device *dssdev; + mgr = omap_dss_get_overlay_manager(i); - if (mgr->device && mgr->device->driver) - mgr->device->driver->disable(mgr->device); + dssdev = mgr->get_device(mgr); + + if (dssdev && dssdev->driver) + dssdev->driver->disable(dssdev); } } @@ -3661,17 +3982,98 @@ static void _omap_dispc_initial_config(void) if (dss_has_feature(FEAT_FUNCGATED)) REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); - _dispc_setup_color_conv_coef(); + dispc_setup_color_conv_coef(); dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY); - dispc_read_plane_fifo_sizes(); + dispc_init_fifos(); dispc_configure_burst_sizes(); dispc_ovl_enable_zorder_planes(); } +static const struct dispc_features omap24xx_dispc_feats __initconst = { + .sw_start = 5, + .fp_start = 15, + .bp_start = 27, + .sw_max = 64, + .vp_max = 255, + .hp_max = 256, + .calc_scaling = dispc_ovl_calc_scaling_24xx, + .calc_core_clk = calc_core_clk_24xx, + .num_fifos = 3, +}; + +static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = { + .sw_start = 5, + .fp_start = 15, + .bp_start = 27, + .sw_max = 64, + .vp_max = 255, + .hp_max = 256, + .calc_scaling = dispc_ovl_calc_scaling_34xx, + .calc_core_clk = calc_core_clk_34xx, + .num_fifos = 3, +}; + +static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = { + .sw_start = 7, + .fp_start = 19, + .bp_start = 31, + .sw_max = 256, + .vp_max = 4095, + .hp_max = 4096, + .calc_scaling = dispc_ovl_calc_scaling_34xx, + .calc_core_clk = calc_core_clk_34xx, + .num_fifos = 3, +}; + +static const struct dispc_features omap44xx_dispc_feats __initconst = { + .sw_start = 7, + .fp_start = 19, + .bp_start = 31, + .sw_max = 256, + .vp_max = 4095, + .hp_max = 4096, + .calc_scaling = dispc_ovl_calc_scaling_44xx, + .calc_core_clk = calc_core_clk_44xx, + .num_fifos = 5, + .gfx_fifo_workaround = true, +}; + +static int __init dispc_init_features(struct device *dev) +{ + const struct dispc_features *src; + struct dispc_features *dst; + + dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL); + if (!dst) { + dev_err(dev, "Failed to allocate DISPC Features\n"); + return -ENOMEM; + } + + if (cpu_is_omap24xx()) { + src = &omap24xx_dispc_feats; + } else if (cpu_is_omap34xx()) { + if (omap_rev() < OMAP3430_REV_ES3_0) + src = &omap34xx_rev1_0_dispc_feats; + else + src = &omap34xx_rev3_0_dispc_feats; + } else if (cpu_is_omap44xx()) { + src = &omap44xx_dispc_feats; + } else if (soc_is_omap54xx()) { + src = &omap44xx_dispc_feats; + } else { + return -ENODEV; + } + + memcpy(dst, src, sizeof(*dst)); + dispc.feat = dst; + + return 0; +} + /* DISPC HW IP initialisation */ static int __init omap_dispchw_probe(struct platform_device *pdev) { @@ -3682,6 +4084,10 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) dispc.pdev = pdev; + r = dispc_init_features(&dispc.pdev->dev); + if (r) + return r; + spin_lock_init(&dispc.irq_lock); #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h index 92d8a9be86fc..222363c6e623 100644 --- a/drivers/video/omap2/dss/dispc.h +++ b/drivers/video/omap2/dss/dispc.h @@ -36,6 +36,7 @@ #define DISPC_CONTROL2 0x0238 #define DISPC_CONFIG2 0x0620 #define DISPC_DIVISOR 0x0804 +#define DISPC_GLOBAL_BUFFER 0x0800 #define DISPC_CONTROL3 0x0848 #define DISPC_CONFIG3 0x084C @@ -355,6 +356,8 @@ static inline u16 DISPC_OVL_BASE(enum omap_plane plane) return 0x014C; case OMAP_DSS_VIDEO3: return 0x0300; + case OMAP_DSS_WB: + return 0x0500; default: BUG(); return 0; @@ -370,6 +373,7 @@ static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0000; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0008; default: BUG(); @@ -385,6 +389,7 @@ static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0004; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x000C; default: BUG(); @@ -404,6 +409,8 @@ static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane) return 0x04BC; case OMAP_DSS_VIDEO3: return 0x0310; + case OMAP_DSS_WB: + return 0x0118; default: BUG(); return 0; @@ -422,6 +429,8 @@ static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane) return 0x04C0; case OMAP_DSS_VIDEO3: return 0x0314; + case OMAP_DSS_WB: + return 0x011C; default: BUG(); return 0; @@ -451,6 +460,7 @@ static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x000C; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x00A8; default: BUG(); @@ -467,6 +477,7 @@ static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0010; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0070; default: BUG(); @@ -486,6 +497,8 @@ static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane) return 0x04DC; case OMAP_DSS_VIDEO3: return 0x032C; + case OMAP_DSS_WB: + return 0x0310; default: BUG(); return 0; @@ -501,6 +514,7 @@ static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0014; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x008C; default: BUG(); @@ -517,6 +531,7 @@ static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0018; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0088; default: BUG(); @@ -533,6 +548,7 @@ static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x001C; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x00A4; default: BUG(); @@ -549,6 +565,7 @@ static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0020; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0098; default: BUG(); @@ -598,6 +615,7 @@ static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0024; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0090; default: BUG(); @@ -617,6 +635,8 @@ static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane) return 0x055C; case OMAP_DSS_VIDEO3: return 0x0424; + case OMAP_DSS_WB: + return 0x290; default: BUG(); return 0; @@ -633,6 +653,7 @@ static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0028; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0094; default: BUG(); @@ -651,6 +672,7 @@ static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x002C; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0000; default: BUG(); @@ -670,6 +692,8 @@ static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane) return 0x0560; case OMAP_DSS_VIDEO3: return 0x0428; + case OMAP_DSS_WB: + return 0x0294; default: BUG(); return 0; @@ -686,6 +710,7 @@ static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane) case OMAP_DSS_VIDEO2: return 0x0030; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0004; default: BUG(); @@ -705,6 +730,8 @@ static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane) return 0x0564; case OMAP_DSS_VIDEO3: return 0x042C; + case OMAP_DSS_WB: + return 0x0298; default: BUG(); return 0; @@ -722,6 +749,7 @@ static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i) case OMAP_DSS_VIDEO2: return 0x0034 + i * 0x8; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0010 + i * 0x8; default: BUG(); @@ -742,6 +770,8 @@ static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i) return 0x0568 + i * 0x8; case OMAP_DSS_VIDEO3: return 0x0430 + i * 0x8; + case OMAP_DSS_WB: + return 0x02A0 + i * 0x8; default: BUG(); return 0; @@ -759,6 +789,7 @@ static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i) case OMAP_DSS_VIDEO2: return 0x0038 + i * 0x8; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0014 + i * 0x8; default: BUG(); @@ -779,6 +810,8 @@ static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i) return 0x056C + i * 0x8; case OMAP_DSS_VIDEO3: return 0x0434 + i * 0x8; + case OMAP_DSS_WB: + return 0x02A4 + i * 0x8; default: BUG(); return 0; @@ -795,6 +828,7 @@ static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i) case OMAP_DSS_VIDEO1: case OMAP_DSS_VIDEO2: case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0074 + i * 0x4; default: BUG(); @@ -814,6 +848,7 @@ static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i) case OMAP_DSS_VIDEO2: return 0x00B4 + i * 0x4; case OMAP_DSS_VIDEO3: + case OMAP_DSS_WB: return 0x0050 + i * 0x4; default: BUG(); @@ -834,6 +869,8 @@ static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i) return 0x05A8 + i * 0x4; case OMAP_DSS_VIDEO3: return 0x0470 + i * 0x4; + case OMAP_DSS_WB: + return 0x02E0 + i * 0x4; default: BUG(); return 0; diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 5bd957e85505..ccf8550fafde 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -142,7 +142,11 @@ static ssize_t display_timings_store(struct device *dev, if (r) return r; + dssdev->driver->disable(dssdev); dssdev->driver->set_timings(dssdev, &t); + r = dssdev->driver->enable(dssdev); + if (r) + return r; return size; } @@ -316,26 +320,117 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev, } EXPORT_SYMBOL(omapdss_default_get_timings); -void dss_init_device(struct platform_device *pdev, +/* + * Connect dssdev to a manager if the manager is free or if force is specified. + * Connect all overlays to that manager if they are free or if force is + * specified. + */ +static int dss_init_connections(struct omap_dss_device *dssdev, bool force) +{ + struct omap_dss_output *out; + struct omap_overlay_manager *mgr; + int i, r; + + out = omapdss_get_output_from_dssdev(dssdev); + + WARN_ON(dssdev->output); + WARN_ON(out->device); + + r = omapdss_output_set_device(out, dssdev); + if (r) { + DSSERR("failed to connect output to new device\n"); + return r; + } + + mgr = omap_dss_get_overlay_manager(dssdev->channel); + + if (mgr->output && !force) + return 0; + + if (mgr->output) + mgr->unset_output(mgr); + + r = mgr->set_output(mgr, out); + if (r) { + DSSERR("failed to connect manager to output of new device\n"); + + /* remove the output-device connection we just made */ + omapdss_output_unset_device(out); + return r; + } + + for (i = 0; i < omap_dss_get_num_overlays(); ++i) { + struct omap_overlay *ovl = omap_dss_get_overlay(i); + + if (!ovl->manager || force) { + if (ovl->manager) + ovl->unset_manager(ovl); + + r = ovl->set_manager(ovl, mgr); + if (r) { + DSSERR("failed to set initial overlay\n"); + return r; + } + } + } + + return 0; +} + +static void dss_uninit_connections(struct omap_dss_device *dssdev) +{ + if (dssdev->output) { + struct omap_overlay_manager *mgr = dssdev->output->manager; + + if (mgr) + mgr->unset_output(mgr); + + omapdss_output_unset_device(dssdev->output); + } +} + +int dss_init_device(struct platform_device *pdev, struct omap_dss_device *dssdev) { struct device_attribute *attr; - int i; - int r; + int i, r; + const char *def_disp_name = dss_get_default_display_name(); + bool force; + + force = def_disp_name && strcmp(def_disp_name, dssdev->name) == 0; + dss_init_connections(dssdev, force); /* create device sysfs files */ i = 0; while ((attr = display_sysfs_attrs[i++]) != NULL) { r = device_create_file(&dssdev->dev, attr); - if (r) + if (r) { + for (i = i - 2; i >= 0; i--) { + attr = display_sysfs_attrs[i]; + device_remove_file(&dssdev->dev, attr); + } + + dss_uninit_connections(dssdev); + DSSERR("failed to create sysfs file\n"); + return r; + } } /* create display? sysfs links */ r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj, dev_name(&dssdev->dev)); - if (r) + if (r) { + while ((attr = display_sysfs_attrs[i++]) != NULL) + device_remove_file(&dssdev->dev, attr); + + dss_uninit_connections(dssdev); + DSSERR("failed to create sysfs display link\n"); + return r; + } + + return 0; } void dss_uninit_device(struct platform_device *pdev, @@ -349,8 +444,7 @@ void dss_uninit_device(struct platform_device *pdev, while ((attr = display_sysfs_attrs[i++]) != NULL) device_remove_file(&dssdev->dev, attr); - if (dssdev->manager) - dssdev->manager->unset_device(dssdev->manager); + dss_uninit_connections(dssdev); } static int dss_suspend_device(struct device *dev, void *data) diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 3266be23fc0d..56748cf8760e 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -29,17 +29,24 @@ #include <linux/errno.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> +#include <linux/string.h> #include <video/omapdss.h> -#include <plat/cpu.h> #include "dss.h" +#include "dss_features.h" static struct { struct regulator *vdds_dsi_reg; struct platform_device *dsidev; + struct mutex lock; + + struct omap_video_timings timings; struct dss_lcd_mgr_config mgr_config; + int data_lines; + + struct omap_dss_output output; } dpi; static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk) @@ -121,7 +128,8 @@ static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, static int dpi_set_mode(struct omap_dss_device *dssdev) { - struct omap_video_timings *t = &dssdev->panel.timings; + struct omap_video_timings *t = &dpi.timings; + struct omap_overlay_manager *mgr = dssdev->output->manager; int lck_div = 0, pck_div = 0; unsigned long fck = 0; unsigned long pck; @@ -146,37 +154,44 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) t->pixel_clock = pck; } - dss_mgr_set_timings(dssdev->manager, t); + dss_mgr_set_timings(mgr, t); return 0; } static void dpi_config_lcd_manager(struct omap_dss_device *dssdev) { + struct omap_overlay_manager *mgr = dssdev->output->manager; + dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; dpi.mgr_config.stallmode = false; dpi.mgr_config.fifohandcheck = false; - dpi.mgr_config.video_port_width = dssdev->phy.dpi.data_lines; + dpi.mgr_config.video_port_width = dpi.data_lines; dpi.mgr_config.lcden_sig_polarity = 0; - dss_mgr_set_lcd_config(dssdev->manager, &dpi.mgr_config); + dss_mgr_set_lcd_config(mgr, &dpi.mgr_config); } int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) { + struct omap_dss_output *out = dssdev->output; int r; - if (cpu_is_omap34xx() && !dpi.vdds_dsi_reg) { + mutex_lock(&dpi.lock); + + if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) { DSSERR("no VDSS_DSI regulator\n"); - return -ENODEV; + r = -ENODEV; + goto err_no_reg; } - if (dssdev->manager == NULL) { - DSSERR("failed to enable display: no manager\n"); - return -ENODEV; + if (out == NULL || out->manager == NULL) { + DSSERR("failed to enable display: no output/manager\n"); + r = -ENODEV; + goto err_no_out_mgr; } r = omap_dss_start_device(dssdev); @@ -185,7 +200,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) goto err_start_dev; } - if (cpu_is_omap34xx()) { + if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) { r = regulator_enable(dpi.vdds_dsi_reg); if (r) goto err_reg_enable; @@ -195,6 +210,10 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) if (r) goto err_get_dispc; + r = dss_dpi_select_source(dssdev->channel); + if (r) + goto err_src_sel; + if (dpi_use_dsi_pll(dssdev)) { r = dsi_runtime_get(dpi.dsidev); if (r) @@ -213,10 +232,12 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) mdelay(2); - r = dss_mgr_enable(dssdev->manager); + r = dss_mgr_enable(out->manager); if (r) goto err_mgr_enable; + mutex_unlock(&dpi.lock); + return 0; err_mgr_enable: @@ -227,20 +248,28 @@ err_dsi_pll_init: if (dpi_use_dsi_pll(dssdev)) dsi_runtime_put(dpi.dsidev); err_get_dsi: +err_src_sel: dispc_runtime_put(); err_get_dispc: - if (cpu_is_omap34xx()) + if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) regulator_disable(dpi.vdds_dsi_reg); err_reg_enable: omap_dss_stop_device(dssdev); err_start_dev: +err_no_out_mgr: +err_no_reg: + mutex_unlock(&dpi.lock); return r; } EXPORT_SYMBOL(omapdss_dpi_display_enable); void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) { - dss_mgr_disable(dssdev->manager); + struct omap_overlay_manager *mgr = dssdev->output->manager; + + mutex_lock(&dpi.lock); + + dss_mgr_disable(mgr); if (dpi_use_dsi_pll(dssdev)) { dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); @@ -250,44 +279,39 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) dispc_runtime_put(); - if (cpu_is_omap34xx()) + if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) regulator_disable(dpi.vdds_dsi_reg); omap_dss_stop_device(dssdev); + + mutex_unlock(&dpi.lock); } EXPORT_SYMBOL(omapdss_dpi_display_disable); -void dpi_set_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings) +void omapdss_dpi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) { - int r; - DSSDBG("dpi_set_timings\n"); - dssdev->panel.timings = *timings; - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - r = dispc_runtime_get(); - if (r) - return; - dpi_set_mode(dssdev); + mutex_lock(&dpi.lock); - dispc_runtime_put(); - } else { - dss_mgr_set_timings(dssdev->manager, timings); - } + dpi.timings = *timings; + + mutex_unlock(&dpi.lock); } -EXPORT_SYMBOL(dpi_set_timings); +EXPORT_SYMBOL(omapdss_dpi_set_timings); int dpi_check_timings(struct omap_dss_device *dssdev, struct omap_video_timings *timings) { int r; + struct omap_overlay_manager *mgr = dssdev->output->manager; int lck_div, pck_div; unsigned long fck; unsigned long pck; struct dispc_clock_info dispc_cinfo; - if (dss_mgr_check_timings(dssdev->manager, timings)) + if (dss_mgr_check_timings(mgr, timings)) return -EINVAL; if (timings->pixel_clock == 0) @@ -325,11 +349,22 @@ int dpi_check_timings(struct omap_dss_device *dssdev, } EXPORT_SYMBOL(dpi_check_timings); +void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) +{ + mutex_lock(&dpi.lock); + + dpi.data_lines = data_lines; + + mutex_unlock(&dpi.lock); +} +EXPORT_SYMBOL(omapdss_dpi_set_data_lines); + static int __init dpi_init_display(struct omap_dss_device *dssdev) { DSSDBG("init_display\n"); - if (cpu_is_omap34xx() && dpi.vdds_dsi_reg == NULL) { + if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && + dpi.vdds_dsi_reg == NULL) { struct regulator *vdds_dsi; vdds_dsi = dss_get_vdds_dsi(); @@ -351,10 +386,14 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev) return 0; } -static void __init dpi_probe_pdata(struct platform_device *pdev) +static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - int i, r; + const char *def_disp_name = dss_get_default_display_name(); + struct omap_dss_device *def_dssdev; + int i; + + def_dssdev = NULL; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -362,21 +401,75 @@ static void __init dpi_probe_pdata(struct platform_device *pdev) if (dssdev->type != OMAP_DISPLAY_TYPE_DPI) continue; - r = dpi_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - continue; + if (def_dssdev == NULL) + def_dssdev = dssdev; + + if (def_disp_name != NULL && + strcmp(dssdev->name, def_disp_name) == 0) { + def_dssdev = dssdev; + break; } + } - r = omap_dss_register_device(dssdev, &pdev->dev, i); - if (r) - DSSERR("device %s register failed: %d\n", - dssdev->name, r); + return def_dssdev; +} + +static void __init dpi_probe_pdata(struct platform_device *dpidev) +{ + struct omap_dss_device *plat_dssdev; + struct omap_dss_device *dssdev; + int r; + + plat_dssdev = dpi_find_dssdev(dpidev); + + if (!plat_dssdev) + return; + + dssdev = dss_alloc_and_init_device(&dpidev->dev); + if (!dssdev) + return; + + dss_copy_device_pdata(dssdev, plat_dssdev); + + r = dpi_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; + } + + r = dss_add_device(dssdev); + if (r) { + DSSERR("device %s register failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; } } +static void __init dpi_init_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &dpi.output; + + out->pdev = pdev; + out->id = OMAP_DSS_OUTPUT_DPI; + out->type = OMAP_DISPLAY_TYPE_DPI; + + dss_register_output(out); +} + +static void __exit dpi_uninit_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &dpi.output; + + dss_unregister_output(out); +} + static int __init omap_dpi_probe(struct platform_device *pdev) { + mutex_init(&dpi.lock); + + dpi_init_output(pdev); + dpi_probe_pdata(pdev); return 0; @@ -384,7 +477,9 @@ static int __init omap_dpi_probe(struct platform_device *pdev) static int __exit omap_dpi_remove(struct platform_device *pdev) { - omap_dss_unregister_child_devices(&pdev->dev); + dss_unregister_child_devices(&pdev->dev); + + dpi_uninit_output(pdev); return 0; } diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 05ee04667af1..d64ac3842884 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -41,7 +41,6 @@ #include <video/omapdss.h> #include <video/mipi_display.h> -#include <plat/clock.h> #include "dss.h" #include "dss_features.h" @@ -333,6 +332,12 @@ struct dsi_data { unsigned scp_clk_refcount; struct dss_lcd_mgr_config mgr_config; + struct omap_video_timings timings; + enum omap_dss_dsi_pixel_format pix_fmt; + enum omap_dss_dsi_mode mode; + struct omap_dss_dsi_videomode_timings vm_timings; + + struct omap_dss_output output; }; struct dsi_packet_sent_handler_data { @@ -340,8 +345,6 @@ struct dsi_packet_sent_handler_data { struct completion *completion; }; -static struct platform_device *dsi_pdev_map[MAX_NUM_DSI]; - #ifdef DEBUG static bool dsi_perf; module_param(dsi_perf, bool, 0644); @@ -354,12 +357,19 @@ static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dside static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev) { - return dsi_pdev_map[dssdev->phy.dsi.module]; + return dssdev->output->pdev; } struct platform_device *dsi_get_dsidev_from_id(int module) { - return dsi_pdev_map[module]; + struct omap_dss_output *out; + enum omap_dss_output_id id; + + id = module == 0 ? OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; + + out = omap_dss_get_output(id); + + return out->pdev; } static inline void dsi_write_reg(struct platform_device *dsidev, @@ -1450,6 +1460,148 @@ found: return 0; } +static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev, + unsigned long req_clkin4ddr, struct dsi_clock_info *cinfo) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_clock_info cur, best; + + DSSDBG("dsi_pll_calc_ddrfreq\n"); + + memset(&best, 0, sizeof(best)); + memset(&cur, 0, sizeof(cur)); + + cur.clkin = clk_get_rate(dsi->sys_clk); + + for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) { + cur.fint = cur.clkin / cur.regn; + + if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min) + continue; + + /* DSIPHY(MHz) = (2 * regm / regn) * clkin */ + for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) { + unsigned long a, b; + + a = 2 * cur.regm * (cur.clkin/1000); + b = cur.regn; + cur.clkin4ddr = a / b * 1000; + + if (cur.clkin4ddr > 1800 * 1000 * 1000) + break; + + if (abs(cur.clkin4ddr - req_clkin4ddr) < + abs(best.clkin4ddr - req_clkin4ddr)) { + best = cur; + DSSDBG("best %ld\n", best.clkin4ddr); + } + + if (cur.clkin4ddr == req_clkin4ddr) + goto found; + } + } +found: + if (cinfo) + *cinfo = best; + + return 0; +} + +static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev, + struct dsi_clock_info *cinfo) +{ + unsigned long max_dsi_fck; + + max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK); + + cinfo->regm_dsi = DIV_ROUND_UP(cinfo->clkin4ddr, max_dsi_fck); + cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi; +} + +static int dsi_pll_calc_dispc_fck(struct platform_device *dsidev, + unsigned long req_pck, struct dsi_clock_info *cinfo, + struct dispc_clock_info *dispc_cinfo) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + unsigned regm_dispc, best_regm_dispc; + unsigned long dispc_clk, best_dispc_clk; + int min_fck_per_pck; + unsigned long max_dss_fck; + struct dispc_clock_info best_dispc; + bool match; + + max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); + + min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; + + if (min_fck_per_pck && + req_pck * min_fck_per_pck > max_dss_fck) { + DSSERR("Requested pixel clock not possible with the current " + "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning " + "the constraint off.\n"); + min_fck_per_pck = 0; + } + +retry: + best_regm_dispc = 0; + best_dispc_clk = 0; + memset(&best_dispc, 0, sizeof(best_dispc)); + match = false; + + for (regm_dispc = 1; regm_dispc < dsi->regm_dispc_max; ++regm_dispc) { + struct dispc_clock_info cur_dispc; + + dispc_clk = cinfo->clkin4ddr / regm_dispc; + + /* this will narrow down the search a bit, + * but still give pixclocks below what was + * requested */ + if (dispc_clk < req_pck) + break; + + if (dispc_clk > max_dss_fck) + continue; + + if (min_fck_per_pck && dispc_clk < req_pck * min_fck_per_pck) + continue; + + match = true; + + dispc_find_clk_divs(req_pck, dispc_clk, &cur_dispc); + + if (abs(cur_dispc.pck - req_pck) < + abs(best_dispc.pck - req_pck)) { + best_regm_dispc = regm_dispc; + best_dispc_clk = dispc_clk; + best_dispc = cur_dispc; + + if (cur_dispc.pck == req_pck) + goto found; + } + } + + if (!match) { + if (min_fck_per_pck) { + DSSERR("Could not find suitable clock settings.\n" + "Turning FCK/PCK constraint off and" + "trying again.\n"); + min_fck_per_pck = 0; + goto retry; + } + + DSSERR("Could not find suitable clock settings.\n"); + + return -EINVAL; + } +found: + cinfo->regm_dispc = best_regm_dispc; + cinfo->dsi_pll_hsdiv_dispc_clk = best_dispc_clk; + + *dispc_cinfo = best_dispc; + + return 0; +} + int dsi_pll_set_clock_div(struct platform_device *dsidev, struct dsi_clock_info *cinfo) { @@ -1526,21 +1678,27 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max); + l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2); + if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) { f = cinfo->fint < 1000000 ? 0x3 : cinfo->fint < 1250000 ? 0x4 : cinfo->fint < 1500000 ? 0x5 : cinfo->fint < 1750000 ? 0x6 : 0x7; - } - l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2); - - if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */ + } else if (dss_has_feature(FEAT_DSI_PLL_SELFREQDCO)) { + f = cinfo->clkin4ddr < 1000000000 ? 0x2 : 0x4; + + l = FLD_MOD(l, f, 4, 1); /* PLL_SELFREQDCO */ + } + l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */ l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */ l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */ + if (dss_has_feature(FEAT_DSI_PLL_REFSEL)) + l = FLD_MOD(l, 3, 22, 21); /* REF_SYSCLK = sysclk */ dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l); REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */ @@ -2004,15 +2162,16 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) return 1194 * 3; /* 1194x24 bits */ case 6: return 1365 * 3; /* 1365x24 bits */ + case 7: + return 1920 * 3; /* 1920x24 bits */ default: BUG(); return 0; } } -static int dsi_set_lane_config(struct omap_dss_device *dssdev) +static int dsi_set_lane_config(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); static const u8 offsets[] = { 0, 4, 8, 12, 16 }; static const enum dsi_lane_function functions[] = { @@ -2136,9 +2295,16 @@ static void dsi_cio_timings(struct platform_device *dsidev) dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r); r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); - r = FLD_MOD(r, tlpx_half, 22, 16); + r = FLD_MOD(r, tlpx_half, 20, 16); r = FLD_MOD(r, tclk_trail, 15, 8); r = FLD_MOD(r, tclk_zero, 7, 0); + + if (dss_has_feature(FEAT_DSI_PHY_DCC)) { + r = FLD_MOD(r, 0, 21, 21); /* DCCEN = disable */ + r = FLD_MOD(r, 1, 22, 22); /* CLKINP_DIVBY2EN = enable */ + r = FLD_MOD(r, 1, 23, 23); /* CLKINP_SEL = enable */ + } + dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r); r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2); @@ -2147,10 +2313,9 @@ static void dsi_cio_timings(struct platform_device *dsidev) } /* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */ -static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev, +static void dsi_cio_enable_lane_override(struct platform_device *dsidev, unsigned mask_p, unsigned mask_n) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int i; u32 l; @@ -2197,9 +2362,8 @@ static void dsi_cio_disable_lane_override(struct platform_device *dsidev) REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17); } -static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) +static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int t, i; bool in_use[DSI_MAX_NR_LANES]; @@ -2247,9 +2411,8 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) } /* return bitmask of enabled lanes, lane0 being the lsb */ -static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev) +static unsigned dsi_get_lane_mask(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned mask = 0; int i; @@ -2262,16 +2425,15 @@ static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev) return mask; } -static int dsi_cio_init(struct omap_dss_device *dssdev) +static int dsi_cio_init(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; u32 l; DSSDBGF(); - r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dssdev)); + r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); if (r) return r; @@ -2288,7 +2450,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) goto err_scp_clk_dom; } - r = dsi_set_lane_config(dssdev); + r = dsi_set_lane_config(dsidev); if (r) goto err_scp_clk_dom; @@ -2323,7 +2485,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) mask_p |= 1 << i; } - dsi_cio_enable_lane_override(dssdev, mask_p, 0); + dsi_cio_enable_lane_override(dsidev, mask_p, 0); } r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON); @@ -2340,7 +2502,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) dsi_if_enable(dsidev, false); REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */ - r = dsi_cio_wait_tx_clk_esc_reset(dssdev); + r = dsi_cio_wait_tx_clk_esc_reset(dsidev); if (r) goto err_tx_clk_esc_rst; @@ -2360,10 +2522,10 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) dsi_cio_timings(dsidev); - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { /* DDR_CLK_ALWAYS_ON */ REG_FLD_MOD(dsidev, DSI_CLK_CTRL, - dssdev->panel.dsi_vm_data.ddr_clk_always_on, 13, 13); + dsi->vm_timings.ddr_clk_always_on, 13, 13); } dsi->ulps_enabled = false; @@ -2381,13 +2543,12 @@ err_cio_pwr: dsi_cio_disable_lane_override(dsidev); err_scp_clk_dom: dsi_disable_scp_clk(dsidev); - dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev)); + dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); return r; } -static void dsi_cio_uninit(struct omap_dss_device *dssdev) +static void dsi_cio_uninit(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); /* DDR_CLK_ALWAYS_ON */ @@ -2395,7 +2556,7 @@ static void dsi_cio_uninit(struct omap_dss_device *dssdev) dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF); dsi_disable_scp_clk(dsidev); - dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev)); + dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); } static void dsi_config_tx_fifo(struct platform_device *dsidev, @@ -2685,6 +2846,7 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, bool enable) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable); @@ -2701,7 +2863,7 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, dsi_force_tx_stop_mode_io(dsidev); /* start the DDR clock by sending a NULL packet */ - if (dssdev->panel.dsi_vm_data.ddr_clk_always_on && enable) + if (dsi->vm_timings.ddr_clk_always_on && enable) dsi_vc_send_null(dssdev, channel); } EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs); @@ -2987,10 +3149,9 @@ int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel) } EXPORT_SYMBOL(dsi_vc_send_null); -static int dsi_vc_write_nosync_common(struct omap_dss_device *dssdev, +static int dsi_vc_write_nosync_common(struct platform_device *dsidev, int channel, u8 *data, int len, enum dss_dsi_content_type type) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); int r; if (len == 0) { @@ -3021,7 +3182,9 @@ static int dsi_vc_write_nosync_common(struct omap_dss_device *dssdev, int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel, u8 *data, int len) { - return dsi_vc_write_nosync_common(dssdev, channel, data, len, + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + + return dsi_vc_write_nosync_common(dsidev, channel, data, len, DSS_DSI_CONTENT_DCS); } EXPORT_SYMBOL(dsi_vc_dcs_write_nosync); @@ -3029,7 +3192,9 @@ EXPORT_SYMBOL(dsi_vc_dcs_write_nosync); int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel, u8 *data, int len) { - return dsi_vc_write_nosync_common(dssdev, channel, data, len, + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + + return dsi_vc_write_nosync_common(dsidev, channel, data, len, DSS_DSI_CONTENT_GENERIC); } EXPORT_SYMBOL(dsi_vc_generic_write_nosync); @@ -3040,7 +3205,7 @@ static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel, struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); int r; - r = dsi_vc_write_nosync_common(dssdev, channel, data, len, type); + r = dsi_vc_write_nosync_common(dsidev, channel, data, len, type); if (r) goto err; @@ -3118,10 +3283,9 @@ int dsi_vc_generic_write_2(struct omap_dss_device *dssdev, int channel, } EXPORT_SYMBOL(dsi_vc_generic_write_2); -static int dsi_vc_dcs_send_read_request(struct omap_dss_device *dssdev, +static int dsi_vc_dcs_send_read_request(struct platform_device *dsidev, int channel, u8 dcs_cmd) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; @@ -3139,10 +3303,9 @@ static int dsi_vc_dcs_send_read_request(struct omap_dss_device *dssdev, return 0; } -static int dsi_vc_generic_send_read_request(struct omap_dss_device *dssdev, +static int dsi_vc_generic_send_read_request(struct platform_device *dsidev, int channel, u8 *reqdata, int reqlen) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u16 data; u8 data_type; @@ -3291,7 +3454,7 @@ int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); int r; - r = dsi_vc_dcs_send_read_request(dssdev, channel, dcs_cmd); + r = dsi_vc_dcs_send_read_request(dsidev, channel, dcs_cmd); if (r) goto err; @@ -3322,7 +3485,7 @@ static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel, struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); int r; - r = dsi_vc_generic_send_read_request(dssdev, channel, reqdata, reqlen); + r = dsi_vc_generic_send_read_request(dsidev, channel, reqdata, reqlen); if (r) return r; @@ -3604,15 +3767,15 @@ static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev) +static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int num_line_buffers; - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { - int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { + int bpp = dsi_get_pixel_size(dsi->pix_fmt); unsigned line_buf_size = dsi_get_line_buf_size(dsidev); - struct omap_video_timings *timings = &dssdev->panel.timings; + struct omap_video_timings *timings = &dsi->timings; /* * Don't use line buffers if width is greater than the video * port's line buffer size @@ -3630,11 +3793,11 @@ static void dsi_config_vp_num_line_buffers(struct omap_dss_device *dssdev) REG_FLD_MOD(dsidev, DSI_CTRL, num_line_buffers, 13, 12); } -static void dsi_config_vp_sync_events(struct omap_dss_device *dssdev) +static void dsi_config_vp_sync_events(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - bool vsync_end = dssdev->panel.dsi_vm_data.vp_vsync_end; - bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end; + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + bool vsync_end = dsi->vm_timings.vp_vsync_end; + bool hsync_end = dsi->vm_timings.vp_hsync_end; u32 r; r = dsi_read_reg(dsidev, DSI_CTRL); @@ -3648,13 +3811,13 @@ static void dsi_config_vp_sync_events(struct omap_dss_device *dssdev) dsi_write_reg(dsidev, DSI_CTRL, r); } -static void dsi_config_blanking_modes(struct omap_dss_device *dssdev) +static void dsi_config_blanking_modes(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - int blanking_mode = dssdev->panel.dsi_vm_data.blanking_mode; - int hfp_blanking_mode = dssdev->panel.dsi_vm_data.hfp_blanking_mode; - int hbp_blanking_mode = dssdev->panel.dsi_vm_data.hbp_blanking_mode; - int hsa_blanking_mode = dssdev->panel.dsi_vm_data.hsa_blanking_mode; + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + int blanking_mode = dsi->vm_timings.blanking_mode; + int hfp_blanking_mode = dsi->vm_timings.hfp_blanking_mode; + int hbp_blanking_mode = dsi->vm_timings.hbp_blanking_mode; + int hsa_blanking_mode = dsi->vm_timings.hsa_blanking_mode; u32 r; /* @@ -3741,8 +3904,8 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev) int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat; int tclk_trail, ths_exit, exiths_clk; bool ddr_alwon; - struct omap_video_timings *timings = &dssdev->panel.timings; - int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + struct omap_video_timings *timings = &dsi->timings; + int bpp = dsi_get_pixel_size(dsi->pix_fmt); int ndl = dsi->num_lanes_used - 1; int dsi_fclk_hsdiv = dssdev->clocks.dsi.regm_dsi + 1; int hsa_interleave_hs = 0, hsa_interleave_lp = 0; @@ -3852,6 +4015,7 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev) static int dsi_proto_config(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); u32 r; int buswidth = 0; @@ -3871,7 +4035,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true); dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true); - switch (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt)) { + switch (dsi_get_pixel_size(dsi->pix_fmt)) { case 16: buswidth = 0; break; @@ -3903,11 +4067,11 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) dsi_write_reg(dsidev, DSI_CTRL, r); - dsi_config_vp_num_line_buffers(dssdev); + dsi_config_vp_num_line_buffers(dsidev); - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { - dsi_config_vp_sync_events(dssdev); - dsi_config_blanking_modes(dssdev); + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { + dsi_config_vp_sync_events(dsidev); + dsi_config_blanking_modes(dsidev); dsi_config_cmd_mode_interleaving(dssdev); } @@ -3919,9 +4083,8 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) return 0; } -static void dsi_proto_timings(struct omap_dss_device *dssdev) +static void dsi_proto_timings(struct platform_device *dsidev) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail; unsigned tclk_pre, tclk_post; @@ -3941,7 +4104,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) ths_exit = FLD_GET(r, 7, 0); r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); - tlpx = FLD_GET(r, 22, 16) * 2; + tlpx = FLD_GET(r, 20, 16) * 2; tclk_trail = FLD_GET(r, 15, 8); tclk_zero = FLD_GET(r, 7, 0); @@ -3984,18 +4147,18 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n", enter_hs_mode_lat, exit_hs_mode_lat); - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { /* TODO: Implement a video mode check_timings function */ - int hsa = dssdev->panel.dsi_vm_data.hsa; - int hfp = dssdev->panel.dsi_vm_data.hfp; - int hbp = dssdev->panel.dsi_vm_data.hbp; - int vsa = dssdev->panel.dsi_vm_data.vsa; - int vfp = dssdev->panel.dsi_vm_data.vfp; - int vbp = dssdev->panel.dsi_vm_data.vbp; - int window_sync = dssdev->panel.dsi_vm_data.window_sync; - bool hsync_end = dssdev->panel.dsi_vm_data.vp_hsync_end; - struct omap_video_timings *timings = &dssdev->panel.timings; - int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + int hsa = dsi->vm_timings.hsa; + int hfp = dsi->vm_timings.hfp; + int hbp = dsi->vm_timings.hbp; + int vsa = dsi->vm_timings.vsa; + int vfp = dsi->vm_timings.vfp; + int vbp = dsi->vm_timings.vbp; + int window_sync = dsi->vm_timings.window_sync; + bool hsync_end = dsi->vm_timings.vp_hsync_end; + struct omap_video_timings *timings = &dsi->timings; + int bpp = dsi_get_pixel_size(dsi->pix_fmt); int tl, t_he, width_bytes; t_he = hsync_end ? @@ -4100,16 +4263,84 @@ int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev, } EXPORT_SYMBOL(omapdss_dsi_configure_pins); -int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) +int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev, + unsigned long ddr_clk, unsigned long lp_clk) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct dsi_clock_info cinfo; + struct dispc_clock_info dispc_cinfo; + unsigned lp_clk_div; + unsigned long dsi_fclk; int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + unsigned long pck; + int r; + + DSSDBGF("ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk); + + mutex_lock(&dsi->lock); + + /* Calculate PLL output clock */ + r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk * 4, &cinfo); + if (r) + goto err; + + /* Calculate PLL's DSI clock */ + dsi_pll_calc_dsi_fck(dsidev, &cinfo); + + /* Calculate PLL's DISPC clock and pck & lck divs */ + pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp; + DSSDBG("finding dispc dividers for pck %lu\n", pck); + r = dsi_pll_calc_dispc_fck(dsidev, pck, &cinfo, &dispc_cinfo); + if (r) + goto err; + + /* Calculate LP clock */ + dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk; + lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2); + + dssdev->clocks.dsi.regn = cinfo.regn; + dssdev->clocks.dsi.regm = cinfo.regm; + dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc; + dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi; + + dssdev->clocks.dsi.lp_clk_div = lp_clk_div; + + dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div; + dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div; + + dssdev->clocks.dispc.dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK; + + dssdev->clocks.dispc.channel.lcd_clk_src = + dsi->module_id == 0 ? + OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : + OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC; + + dssdev->clocks.dsi.dsi_fclk_src = + dsi->module_id == 0 ? + OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI : + OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI; + + mutex_unlock(&dsi->lock); + return 0; +err: + mutex_unlock(&dsi->lock); + return r; +} +EXPORT_SYMBOL(omapdss_dsi_set_clocks); + +int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; + int bpp = dsi_get_pixel_size(dsi->pix_fmt); u8 data_type; u16 word_count; int r; - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { - switch (dssdev->panel.dsi_pix_fmt) { + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { + switch (dsi->pix_fmt) { case OMAP_DSS_DSI_FMT_RGB888: data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; break; @@ -4133,7 +4364,7 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) /* MODE, 1 = video mode */ REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4); - word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8); + word_count = DIV_ROUND_UP(dsi->timings.x_res * bpp, 8); dsi_vc_write_long_header(dsidev, channel, data_type, word_count, 0); @@ -4142,9 +4373,9 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) dsi_if_enable(dsidev, true); } - r = dss_mgr_enable(dssdev->manager); + r = dss_mgr_enable(mgr); if (r) { - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { dsi_if_enable(dsidev, false); dsi_vc_enable(dsidev, channel, false); } @@ -4159,8 +4390,10 @@ EXPORT_SYMBOL(dsi_enable_video_output); void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { + if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { dsi_if_enable(dsidev, false); dsi_vc_enable(dsidev, channel, false); @@ -4171,15 +4404,15 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) dsi_if_enable(dsidev, true); } - dss_mgr_disable(dssdev->manager); + dss_mgr_disable(mgr); } EXPORT_SYMBOL(dsi_disable_video_output); -static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, - u16 w, u16 h) +static void dsi_update_screen_dispc(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; unsigned bytespp; unsigned bytespl; unsigned bytespf; @@ -4190,12 +4423,14 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, int r; const unsigned channel = dsi->update_channel; const unsigned line_buf_size = dsi_get_line_buf_size(dsidev); + u16 w = dsi->timings.x_res; + u16 h = dsi->timings.y_res; DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h); dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP); - bytespp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8; + bytespp = dsi_get_pixel_size(dsi->pix_fmt) / 8; bytespl = w * bytespp; bytespf = bytespl * h; @@ -4239,7 +4474,9 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, msecs_to_jiffies(250)); BUG_ON(r == 0); - dss_mgr_start_update(dssdev->manager); + dss_mgr_set_timings(mgr, &dsi->timings); + + dss_mgr_start_update(mgr); if (dsi->te_enabled) { /* disable LP_RX_TO, so that we can receive TE. Time to wait @@ -4297,8 +4534,7 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work) static void dsi_framedone_irq_callback(void *data, u32 mask) { - struct omap_dss_device *dssdev = (struct omap_dss_device *) data; - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct platform_device *dsidev = (struct platform_device *) data; struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); /* Note: We get FRAMEDONE when DISPC has finished sending pixels and @@ -4325,13 +4561,14 @@ int omap_dsi_update(struct omap_dss_device *dssdev, int channel, dsi->framedone_callback = callback; dsi->framedone_data = data; - dssdev->driver->get_resolution(dssdev, &dw, &dh); + dw = dsi->timings.x_res; + dh = dsi->timings.y_res; #ifdef DEBUG dsi->update_bytes = dw * dh * - dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8; + dsi_get_pixel_size(dsi->pix_fmt) / 8; #endif - dsi_update_screen_dispc(dssdev, dw, dh); + dsi_update_screen_dispc(dssdev); return 0; } @@ -4367,28 +4604,22 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - struct omap_video_timings timings; + struct omap_overlay_manager *mgr = dssdev->output->manager; int r; u32 irq = 0; - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { - u16 dw, dh; - - dssdev->driver->get_resolution(dssdev, &dw, &dh); - - timings.x_res = dw; - timings.y_res = dh; - timings.hsw = 1; - timings.hfp = 1; - timings.hbp = 1; - timings.vsw = 1; - timings.vfp = 0; - timings.vbp = 0; + if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { + dsi->timings.hsw = 1; + dsi->timings.hfp = 1; + dsi->timings.hbp = 1; + dsi->timings.vsw = 1; + dsi->timings.vfp = 0; + dsi->timings.vbp = 0; - irq = dispc_mgr_get_framedone_irq(dssdev->manager->id); + irq = dispc_mgr_get_framedone_irq(mgr->id); r = omap_dispc_register_isr(dsi_framedone_irq_callback, - (void *) dssdev, irq); + (void *) dsidev, irq); if (r) { DSSERR("can't get FRAMEDONE irq\n"); goto err; @@ -4397,8 +4628,6 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) dsi->mgr_config.stallmode = true; dsi->mgr_config.fifohandcheck = true; } else { - timings = dssdev->panel.timings; - dsi->mgr_config.stallmode = false; dsi->mgr_config.fifohandcheck = false; } @@ -4407,14 +4636,14 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) * override interlace, logic level and edge related parameters in * omap_video_timings with default values */ - timings.interlace = false; - timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH; - timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; - timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; - timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; - timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; + dsi->timings.interlace = false; + dsi->timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH; + dsi->timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; + dsi->timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; + dsi->timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; + dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; - dss_mgr_set_timings(dssdev->manager, &timings); + dss_mgr_set_timings(mgr, &dsi->timings); r = dsi_configure_dispc_clocks(dssdev); if (r) @@ -4422,29 +4651,33 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) dsi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; dsi->mgr_config.video_port_width = - dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + dsi_get_pixel_size(dsi->pix_fmt); dsi->mgr_config.lcden_sig_polarity = 0; - dss_mgr_set_lcd_config(dssdev->manager, &dsi->mgr_config); + dss_mgr_set_lcd_config(mgr, &dsi->mgr_config); return 0; err1: - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) + if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) omap_dispc_unregister_isr(dsi_framedone_irq_callback, - (void *) dssdev, irq); + (void *) dsidev, irq); err: return r; } static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev) { - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; + + if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { u32 irq; - irq = dispc_mgr_get_framedone_irq(dssdev->manager->id); + irq = dispc_mgr_get_framedone_irq(mgr->id); omap_dispc_unregister_isr(dsi_framedone_irq_callback, - (void *) dssdev, irq); + (void *) dsidev, irq); } } @@ -4477,6 +4710,7 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; int r; r = dsi_pll_init(dsidev, true, true); @@ -4489,18 +4723,18 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src); - dss_select_lcd_clk_source(dssdev->manager->id, + dss_select_lcd_clk_source(mgr->id, dssdev->clocks.dispc.channel.lcd_clk_src); DSSDBG("PLL OK\n"); - r = dsi_cio_init(dssdev); + r = dsi_cio_init(dsidev); if (r) goto err2; _dsi_print_reset_status(dsidev); - dsi_proto_timings(dssdev); + dsi_proto_timings(dsidev); dsi_set_lp_clk_divisor(dssdev); if (1) @@ -4520,11 +4754,11 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) return 0; err3: - dsi_cio_uninit(dssdev); + dsi_cio_uninit(dsidev); err2: dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); - dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); err1: dsi_pll_uninit(dsidev, true); @@ -4537,6 +4771,7 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_overlay_manager *mgr = dssdev->output->manager; if (enter_ulps && !dsi->ulps_enabled) dsi_enter_ulps(dsidev); @@ -4550,8 +4785,8 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); - dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK); - dsi_cio_uninit(dssdev); + dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); + dsi_cio_uninit(dsidev); dsi_pll_uninit(dsidev, disconnect_lanes); } @@ -4559,6 +4794,7 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_dss_output *out = dssdev->output; int r = 0; DSSDBG("dsi_display_enable\n"); @@ -4567,8 +4803,8 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) mutex_lock(&dsi->lock); - if (dssdev->manager == NULL) { - DSSERR("failed to enable display: no manager\n"); + if (out == NULL || out->manager == NULL) { + DSSERR("failed to enable display: no output/manager\n"); r = -ENODEV; goto err_start_dev; } @@ -4653,17 +4889,83 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable) } EXPORT_SYMBOL(omapdss_dsi_enable_te); -static int __init dsi_init_display(struct omap_dss_device *dssdev) +void omapdss_dsi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - DSSDBG("DSI init\n"); + mutex_lock(&dsi->lock); - if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { - dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | - OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; - } + dsi->timings = *timings; + + mutex_unlock(&dsi->lock); +} +EXPORT_SYMBOL(omapdss_dsi_set_timings); + +void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + mutex_lock(&dsi->lock); + + dsi->timings.x_res = w; + dsi->timings.y_res = h; + + mutex_unlock(&dsi->lock); +} +EXPORT_SYMBOL(omapdss_dsi_set_size); + +void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev, + enum omap_dss_dsi_pixel_format fmt) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + mutex_lock(&dsi->lock); + + dsi->pix_fmt = fmt; + + mutex_unlock(&dsi->lock); +} +EXPORT_SYMBOL(omapdss_dsi_set_pixel_format); + +void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev, + enum omap_dss_dsi_mode mode) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + mutex_lock(&dsi->lock); + + dsi->mode = mode; + + mutex_unlock(&dsi->lock); +} +EXPORT_SYMBOL(omapdss_dsi_set_operation_mode); + +void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev, + struct omap_dss_dsi_videomode_timings *timings) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + mutex_lock(&dsi->lock); + + dsi->vm_timings = *timings; + + mutex_unlock(&dsi->lock); +} +EXPORT_SYMBOL(omapdss_dsi_set_videomode_timings); + +static int __init dsi_init_display(struct omap_dss_device *dssdev) +{ + struct platform_device *dsidev = + dsi_get_dsidev_from_id(dssdev->phy.dsi.module); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + + DSSDBG("DSI init\n"); if (dsi->vdds_dsi_reg == NULL) { struct regulator *vdds_dsi; @@ -4806,11 +5108,15 @@ static void dsi_put_clocks(struct platform_device *dsidev) clk_put(dsi->sys_clk); } -static void __init dsi_probe_pdata(struct platform_device *dsidev) +static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *pdev) { - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - struct omap_dss_board_info *pdata = dsidev->dev.platform_data; - int i, r; + struct omap_dss_board_info *pdata = pdev->dev.platform_data; + struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); + const char *def_disp_name = dss_get_default_display_name(); + struct omap_dss_device *def_dssdev; + int i; + + def_dssdev = NULL; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -4821,19 +5127,73 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev) if (dssdev->phy.dsi.module != dsi->module_id) continue; - r = dsi_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - continue; + if (def_dssdev == NULL) + def_dssdev = dssdev; + + if (def_disp_name != NULL && + strcmp(dssdev->name, def_disp_name) == 0) { + def_dssdev = dssdev; + break; } + } - r = omap_dss_register_device(dssdev, &dsidev->dev, i); - if (r) - DSSERR("device %s register failed: %d\n", - dssdev->name, r); + return def_dssdev; +} + +static void __init dsi_probe_pdata(struct platform_device *dsidev) +{ + struct omap_dss_device *plat_dssdev; + struct omap_dss_device *dssdev; + int r; + + plat_dssdev = dsi_find_dssdev(dsidev); + + if (!plat_dssdev) + return; + + dssdev = dss_alloc_and_init_device(&dsidev->dev); + if (!dssdev) + return; + + dss_copy_device_pdata(dssdev, plat_dssdev); + + r = dsi_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; + } + + r = dss_add_device(dssdev); + if (r) { + DSSERR("device %s register failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; } } +static void __init dsi_init_output(struct platform_device *dsidev) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_dss_output *out = &dsi->output; + + out->pdev = dsidev; + out->id = dsi->module_id == 0 ? + OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; + + out->type = OMAP_DISPLAY_TYPE_DSI; + + dss_register_output(out); +} + +static void __exit dsi_uninit_output(struct platform_device *dsidev) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_dss_output *out = &dsi->output; + + dss_unregister_output(out); +} + /* DSI1 HW IP initialisation */ static int __init omap_dsihw_probe(struct platform_device *dsidev) { @@ -4848,7 +5208,6 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev) dsi->module_id = dsidev->id; dsi->pdev = dsidev; - dsi_pdev_map[dsi->module_id] = dsidev; dev_set_drvdata(&dsidev->dev, dsi); spin_lock_init(&dsi->irq_lock); @@ -4928,6 +5287,8 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev) else dsi->num_lanes_supported = 3; + dsi_init_output(dsidev); + dsi_probe_pdata(dsidev); dsi_runtime_put(dsidev); @@ -4957,7 +5318,9 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev) WARN_ON(dsi->scp_clk_refcount > 0); - omap_dss_unregister_child_devices(&dsidev->dev); + dss_unregister_child_devices(&dsidev->dev); + + dsi_uninit_output(dsidev); pm_runtime_disable(&dsidev->dev); diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 04b4586113e3..2ab1c3e96553 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -31,11 +31,11 @@ #include <linux/clk.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/gfp.h> #include <video/omapdss.h> #include <plat/cpu.h> -#include <plat/clock.h> #include "dss.h" #include "dss_features.h" @@ -65,6 +65,13 @@ struct dss_reg { static int dss_runtime_get(void); static void dss_runtime_put(void); +struct dss_features { + u8 fck_div_max; + u8 dss_fck_multiplier; + const char *clk_name; + int (*dpi_select_source)(enum omap_channel channel); +}; + static struct { struct platform_device *pdev; void __iomem *base; @@ -83,6 +90,8 @@ static struct { bool ctx_valid; u32 ctx[DSS_SZ_REGS / sizeof(u32)]; + + const struct dss_features *feat; } dss; static const char * const dss_generic_clk_source_names[] = { @@ -144,7 +153,7 @@ static void dss_restore_context(void) #undef SR #undef RR -void dss_sdi_init(u8 datapairs) +void dss_sdi_init(int datapairs) { u32 l; @@ -236,7 +245,6 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src) return dss_generic_clk_source_names[clk_src]; } - void dss_dump_clocks(struct seq_file *s) { unsigned long dpll4_ck_rate; @@ -259,18 +267,10 @@ void dss_dump_clocks(struct seq_file *s) seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); - if (cpu_is_omap3630() || cpu_is_omap44xx()) - seq_printf(s, "%s (%s) = %lu / %lu = %lu\n", - fclk_name, fclk_real_name, - dpll4_ck_rate, - dpll4_ck_rate / dpll4_m4_ck_rate, - fclk_rate); - else - seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n", - fclk_name, fclk_real_name, - dpll4_ck_rate, - dpll4_ck_rate / dpll4_m4_ck_rate, - fclk_rate); + seq_printf(s, "%s (%s) = %lu / %lu * %d = %lu\n", + fclk_name, fclk_real_name, dpll4_ck_rate, + dpll4_ck_rate / dpll4_m4_ck_rate, + dss.feat->dss_fck_multiplier, fclk_rate); } else { seq_printf(s, "%s (%s) = %lu\n", fclk_name, fclk_real_name, @@ -431,31 +431,6 @@ enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) } } -/* calculate clock rates using dividers in cinfo */ -int dss_calc_clock_rates(struct dss_clock_info *cinfo) -{ - if (dss.dpll4_m4_ck) { - unsigned long prate; - u16 fck_div_max = 16; - - if (cpu_is_omap3630() || cpu_is_omap44xx()) - fck_div_max = 32; - - if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0) - return -EINVAL; - - prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); - - cinfo->fck = prate / cinfo->fck_div; - } else { - if (cinfo->fck_div != 0) - return -EINVAL; - cinfo->fck = clk_get_rate(dss.dss_clk); - } - - return 0; -} - int dss_set_clock_div(struct dss_clock_info *cinfo) { if (dss.dpll4_m4_ck) { @@ -478,26 +453,6 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) return 0; } -int dss_get_clock_div(struct dss_clock_info *cinfo) -{ - cinfo->fck = clk_get_rate(dss.dss_clk); - - if (dss.dpll4_m4_ck) { - unsigned long prate; - - prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); - - if (cpu_is_omap3630() || cpu_is_omap44xx()) - cinfo->fck_div = prate / (cinfo->fck); - else - cinfo->fck_div = prate / (cinfo->fck / 2); - } else { - cinfo->fck_div = 0; - } - - return 0; -} - unsigned long dss_get_dpll4_rate(void) { if (dss.dpll4_m4_ck) @@ -515,7 +470,7 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, unsigned long fck, max_dss_fck; - u16 fck_div, fck_div_max = 16; + u16 fck_div; int match = 0; int min_fck_per_pck; @@ -525,9 +480,8 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); fck = clk_get_rate(dss.dss_clk); - if (req_pck == dss.cache_req_pck && - ((cpu_is_omap34xx() && prate == dss.cache_prate) || - dss.cache_dss_cinfo.fck == fck)) { + if (req_pck == dss.cache_req_pck && prate == dss.cache_prate && + dss.cache_dss_cinfo.fck == fck) { DSSDBG("dispc clock info found from cache.\n"); *dss_cinfo = dss.cache_dss_cinfo; *dispc_cinfo = dss.cache_dispc_cinfo; @@ -564,16 +518,10 @@ retry: goto found; } else { - if (cpu_is_omap3630() || cpu_is_omap44xx()) - fck_div_max = 32; - - for (fck_div = fck_div_max; fck_div > 0; --fck_div) { + for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) { struct dispc_clock_info cur_dispc; - if (fck_div_max == 32) - fck = prate / fck_div; - else - fck = prate / fck_div * 2; + fck = prate / fck_div * dss.feat->dss_fck_multiplier; if (fck > max_dss_fck) continue; @@ -648,9 +596,18 @@ void dss_set_dac_pwrdn_bgz(bool enable) REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ } -void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi) +void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src) { - REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */ + enum omap_display_type dp; + dp = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT); + + /* Complain about invalid selections */ + WARN_ON((src == DSS_VENC_TV_CLK) && !(dp & OMAP_DISPLAY_TYPE_VENC)); + WARN_ON((src == DSS_HDMI_M_PCLK) && !(dp & OMAP_DISPLAY_TYPE_HDMI)); + + /* Select only if we have options */ + if ((dp & OMAP_DISPLAY_TYPE_VENC) && (dp & OMAP_DISPLAY_TYPE_HDMI)) + REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */ } enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void) @@ -661,9 +618,71 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void) if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0) return DSS_VENC_TV_CLK; + if ((displays & OMAP_DISPLAY_TYPE_VENC) == 0) + return DSS_HDMI_M_PCLK; + return REG_GET(DSS_CONTROL, 15, 15); } +static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel) +{ + if (channel != OMAP_DSS_CHANNEL_LCD) + return -EINVAL; + + return 0; +} + +static int dss_dpi_select_source_omap4(enum omap_channel channel) +{ + int val; + + switch (channel) { + case OMAP_DSS_CHANNEL_LCD2: + val = 0; + break; + case OMAP_DSS_CHANNEL_DIGIT: + val = 1; + break; + default: + return -EINVAL; + } + + REG_FLD_MOD(DSS_CONTROL, val, 17, 17); + + return 0; +} + +static int dss_dpi_select_source_omap5(enum omap_channel channel) +{ + int val; + + switch (channel) { + case OMAP_DSS_CHANNEL_LCD: + val = 1; + break; + case OMAP_DSS_CHANNEL_LCD2: + val = 2; + break; + case OMAP_DSS_CHANNEL_LCD3: + val = 3; + break; + case OMAP_DSS_CHANNEL_DIGIT: + val = 0; + break; + default: + return -EINVAL; + } + + REG_FLD_MOD(DSS_CONTROL, val, 17, 16); + + return 0; +} + +int dss_dpi_select_source(enum omap_channel channel) +{ + return dss.feat->dpi_select_source(channel); +} + static int dss_get_clocks(void) { struct clk *clk; @@ -678,22 +697,11 @@ static int dss_get_clocks(void) dss.dss_clk = clk; - if (cpu_is_omap34xx()) { - clk = clk_get(NULL, "dpll4_m4_ck"); - if (IS_ERR(clk)) { - DSSERR("Failed to get dpll4_m4_ck\n"); - r = PTR_ERR(clk); - goto err; - } - } else if (cpu_is_omap44xx()) { - clk = clk_get(NULL, "dpll_per_m5x2_ck"); - if (IS_ERR(clk)) { - DSSERR("Failed to get dpll_per_m5x2_ck\n"); - r = PTR_ERR(clk); - goto err; - } - } else { /* omap24xx */ - clk = NULL; + clk = clk_get(NULL, dss.feat->clk_name); + if (IS_ERR(clk)) { + DSSERR("Failed to get %s\n", dss.feat->clk_name); + r = PTR_ERR(clk); + goto err; } dss.dpll4_m4_ck = clk; @@ -749,6 +757,71 @@ void dss_debug_dump_clocks(struct seq_file *s) } #endif +static const struct dss_features omap24xx_dss_feats __initconst = { + .fck_div_max = 16, + .dss_fck_multiplier = 2, + .clk_name = NULL, + .dpi_select_source = &dss_dpi_select_source_omap2_omap3, +}; + +static const struct dss_features omap34xx_dss_feats __initconst = { + .fck_div_max = 16, + .dss_fck_multiplier = 2, + .clk_name = "dpll4_m4_ck", + .dpi_select_source = &dss_dpi_select_source_omap2_omap3, +}; + +static const struct dss_features omap3630_dss_feats __initconst = { + .fck_div_max = 32, + .dss_fck_multiplier = 1, + .clk_name = "dpll4_m4_ck", + .dpi_select_source = &dss_dpi_select_source_omap2_omap3, +}; + +static const struct dss_features omap44xx_dss_feats __initconst = { + .fck_div_max = 32, + .dss_fck_multiplier = 1, + .clk_name = "dpll_per_m5x2_ck", + .dpi_select_source = &dss_dpi_select_source_omap4, +}; + +static const struct dss_features omap54xx_dss_feats __initconst = { + .fck_div_max = 64, + .dss_fck_multiplier = 1, + .clk_name = "dpll_per_h12x2_ck", + .dpi_select_source = &dss_dpi_select_source_omap5, +}; + +static int __init dss_init_features(struct device *dev) +{ + const struct dss_features *src; + struct dss_features *dst; + + dst = devm_kzalloc(dev, sizeof(*dst), GFP_KERNEL); + if (!dst) { + dev_err(dev, "Failed to allocate local DSS Features\n"); + return -ENOMEM; + } + + if (cpu_is_omap24xx()) + src = &omap24xx_dss_feats; + else if (cpu_is_omap34xx()) + src = &omap34xx_dss_feats; + else if (cpu_is_omap3630()) + src = &omap3630_dss_feats; + else if (cpu_is_omap44xx()) + src = &omap44xx_dss_feats; + else if (soc_is_omap54xx()) + src = &omap54xx_dss_feats; + else + return -ENODEV; + + memcpy(dst, src, sizeof(*dst)); + dss.feat = dst; + + return 0; +} + /* DSS HW IP initialisation */ static int __init omap_dsshw_probe(struct platform_device *pdev) { @@ -758,6 +831,10 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) dss.pdev = pdev; + r = dss_init_features(&dss.pdev->dev); + if (r) + return r; + dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); if (!dss_mem) { DSSERR("can't get IORESOURCE_MEM DSS\n"); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index f67afe76f217..6728892f9dad 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -113,6 +113,17 @@ enum dss_dsi_content_type { DSS_DSI_CONTENT_GENERIC, }; +enum dss_writeback_channel { + DSS_WB_LCD1_MGR = 0, + DSS_WB_LCD2_MGR = 1, + DSS_WB_TV_MGR = 2, + DSS_WB_OVL0 = 3, + DSS_WB_OVL1 = 4, + DSS_WB_OVL2 = 5, + DSS_WB_OVL3 = 6, + DSS_WB_LCD3_MGR = 7, +}; + struct dss_clock_info { /* rates that we get with dividers below */ unsigned long fck; @@ -175,6 +186,7 @@ struct seq_file; struct platform_device; /* core */ +const char *dss_get_default_display_name(void); struct bus_type *dss_get_bus(void); struct regulator *dss_get_vdds_dsi(void); struct regulator *dss_get_vdds_sdi(void); @@ -184,10 +196,13 @@ void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask); int dss_set_min_bus_tput(struct device *dev, unsigned long tput); int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)); -int omap_dss_register_device(struct omap_dss_device *dssdev, - struct device *parent, int disp_num); -void omap_dss_unregister_device(struct omap_dss_device *dssdev); -void omap_dss_unregister_child_devices(struct device *parent); +struct omap_dss_device *dss_alloc_and_init_device(struct device *parent); +int dss_add_device(struct omap_dss_device *dssdev); +void dss_unregister_device(struct omap_dss_device *dssdev); +void dss_unregister_child_devices(struct device *parent); +void dss_put_device(struct omap_dss_device *dssdev); +void dss_copy_device_pdata(struct omap_dss_device *dst, + const struct omap_dss_device *src); /* apply */ void dss_apply_init(void); @@ -205,8 +220,11 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr, int dss_mgr_set_device(struct omap_overlay_manager *mgr, struct omap_dss_device *dssdev); int dss_mgr_unset_device(struct omap_overlay_manager *mgr); +int dss_mgr_set_output(struct omap_overlay_manager *mgr, + struct omap_dss_output *output); +int dss_mgr_unset_output(struct omap_overlay_manager *mgr); void dss_mgr_set_timings(struct omap_overlay_manager *mgr, - struct omap_video_timings *timings); + const struct omap_video_timings *timings); void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, const struct dss_lcd_mgr_config *config); const struct omap_video_timings *dss_mgr_get_timings(struct omap_overlay_manager *mgr); @@ -222,12 +240,17 @@ int dss_ovl_set_manager(struct omap_overlay *ovl, struct omap_overlay_manager *mgr); int dss_ovl_unset_manager(struct omap_overlay *ovl); +/* output */ +void dss_register_output(struct omap_dss_output *out); +void dss_unregister_output(struct omap_dss_output *out); +struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev); + /* display */ int dss_suspend_all_devices(void); int dss_resume_all_devices(void); void dss_disable_all_devices(void); -void dss_init_device(struct platform_device *pdev, +int dss_init_device(struct platform_device *pdev, struct omap_dss_device *dssdev); void dss_uninit_device(struct platform_device *pdev, struct omap_dss_device *dssdev); @@ -254,22 +277,29 @@ static inline bool dss_mgr_is_lcd(enum omap_channel id) return false; } +int dss_manager_kobj_init(struct omap_overlay_manager *mgr, + struct platform_device *pdev); +void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr); + /* overlay */ void dss_init_overlays(struct platform_device *pdev); void dss_uninit_overlays(struct platform_device *pdev); void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr); -void dss_recheck_connections(struct omap_dss_device *dssdev, bool force); int dss_ovl_simple_check(struct omap_overlay *ovl, const struct omap_overlay_info *info); int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info, const struct omap_video_timings *mgr_timings); bool dss_ovl_use_replication(struct dss_lcd_mgr_config config, enum omap_color_mode mode); +int dss_overlay_kobj_init(struct omap_overlay *ovl, + struct platform_device *pdev); +void dss_overlay_kobj_uninit(struct omap_overlay *ovl); /* DSS */ int dss_init_platform_driver(void) __init; void dss_uninit_platform_driver(void); +int dss_dpi_select_source(enum omap_channel channel); void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); @@ -279,7 +309,7 @@ void dss_dump_clocks(struct seq_file *s); void dss_debug_dump_clocks(struct seq_file *s); #endif -void dss_sdi_init(u8 datapairs); +void dss_sdi_init(int datapairs); int dss_sdi_enable(void); void dss_sdi_disable(void); @@ -296,9 +326,7 @@ void dss_set_venc_output(enum omap_dss_venc_type type); void dss_set_dac_pwrdn_bgz(bool enable); unsigned long dss_get_dpll4_rate(void); -int dss_calc_clock_rates(struct dss_clock_info *cinfo); int dss_set_clock_div(struct dss_clock_info *cinfo); -int dss_get_clock_div(struct dss_clock_info *cinfo); int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, struct dispc_clock_info *dispc_cinfo); @@ -427,8 +455,9 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high); void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, bool manual_update); -int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, - bool replication, const struct omap_video_timings *mgr_timings); +int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, + bool replication, const struct omap_video_timings *mgr_timings, + bool mem_to_mem); int dispc_ovl_enable(enum omap_plane plane, bool enable); void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel); @@ -457,6 +486,15 @@ int dispc_mgr_get_clock_div(enum omap_channel channel, void dispc_mgr_setup(enum omap_channel channel, struct omap_overlay_manager_info *info); +u32 dispc_wb_get_framedone_irq(void); +bool dispc_wb_go_busy(void); +void dispc_wb_go(void); +void dispc_wb_enable(bool enable); +bool dispc_wb_is_enabled(void); +void dispc_wb_set_channel_in(enum dss_writeback_channel channel); +int dispc_wb_setup(const struct omap_dss_writeback_info *wi, + bool mem_to_mem, const struct omap_video_timings *timings); + /* VENC */ #ifdef CONFIG_OMAP2_DSS_VENC int venc_init_platform_driver(void) __init; @@ -469,6 +507,20 @@ static inline unsigned long venc_get_pixel_clock(void) return 0; } #endif +int omapdss_venc_display_enable(struct omap_dss_device *dssdev); +void omapdss_venc_display_disable(struct omap_dss_device *dssdev); +void omapdss_venc_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); +int omapdss_venc_check_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); +u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev); +int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss); +void omapdss_venc_set_type(struct omap_dss_device *dssdev, + enum omap_dss_venc_type type); +void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev, + bool invert_polarity); +int venc_panel_init(void); +void venc_panel_exit(void); /* HDMI */ #ifdef CONFIG_OMAP4_DSS_HDMI @@ -484,7 +536,8 @@ static inline unsigned long hdmi_get_pixel_clock(void) #endif int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev); void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev); -void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev); +void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, struct omap_video_timings *timings); int omapdss_hdmi_read_edid(u8 *buf, int len); diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 938709724f0c..acbc1e1efba3 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -46,7 +46,9 @@ struct omap_dss_features { const int num_mgrs; const int num_ovls; + const int num_wbs; const enum omap_display_type *supported_displays; + const enum omap_dss_output_id *supported_outputs; const enum omap_color_mode *supported_color_modes; const enum omap_overlay_caps *overlay_caps; const char * const *clksrc_names; @@ -106,6 +108,21 @@ static const struct dss_reg_field omap4_dss_reg_fields[] = { [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 }, }; +static const struct dss_reg_field omap5_dss_reg_fields[] = { + [FEAT_REG_FIRHINC] = { 12, 0 }, + [FEAT_REG_FIRVINC] = { 28, 16 }, + [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 }, + [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 }, + [FEAT_REG_FIFOSIZE] = { 15, 0 }, + [FEAT_REG_HORIZONTALACCU] = { 10, 0 }, + [FEAT_REG_VERTICALACCU] = { 26, 16 }, + [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 }, + [FEAT_REG_DSIPLL_REGN] = { 8, 1 }, + [FEAT_REG_DSIPLL_REGM] = { 20, 9 }, + [FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 }, + [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 }, +}; + static const enum omap_display_type omap2_dss_supported_displays[] = { /* OMAP_DSS_CHANNEL_LCD */ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI, @@ -144,6 +161,76 @@ static const enum omap_display_type omap4_dss_supported_displays[] = { OMAP_DISPLAY_TYPE_DSI, }; +static const enum omap_display_type omap5_dss_supported_displays[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | + OMAP_DISPLAY_TYPE_DSI, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DISPLAY_TYPE_HDMI | OMAP_DISPLAY_TYPE_DPI, + + /* OMAP_DSS_CHANNEL_LCD2 */ + OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | + OMAP_DISPLAY_TYPE_DSI, +}; + +static const enum omap_dss_output_id omap2_dss_supported_outputs[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DSS_OUTPUT_VENC, +}; + +static const enum omap_dss_output_id omap3430_dss_supported_outputs[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_SDI | OMAP_DSS_OUTPUT_DSI1, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DSS_OUTPUT_VENC, +}; + +static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_DSI1, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DSS_OUTPUT_VENC, +}; + +static const enum omap_dss_output_id omap4_dss_supported_outputs[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_DSI1, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI | + OMAP_DSS_OUTPUT_DPI, + + /* OMAP_DSS_CHANNEL_LCD2 */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_DSI2, +}; + +static const enum omap_dss_output_id omap5_dss_supported_outputs[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DSS_OUTPUT_HDMI | OMAP_DSS_OUTPUT_DPI, + + /* OMAP_DSS_CHANNEL_LCD2 */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_DSI1, + + /* OMAP_DSS_CHANNEL_LCD3 */ + OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | + OMAP_DSS_OUTPUT_DSI2, +}; + static const enum omap_color_mode omap2_dss_supported_color_modes[] = { /* OMAP_DSS_GFX */ OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 | @@ -224,58 +311,80 @@ static const enum omap_color_mode omap4_dss_supported_color_modes[] = { OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 | OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 | OMAP_DSS_COLOR_RGBX32, + + /* OMAP_DSS_WB */ + OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U | + OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 | + OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 | + OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U | + OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY | + OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 | + OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 | + OMAP_DSS_COLOR_RGBX32, }; static const enum omap_overlay_caps omap2_dss_overlay_caps[] = { /* OMAP_DSS_GFX */ - 0, + OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO1 */ - OMAP_DSS_OVL_CAP_SCALE, + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO2 */ - OMAP_DSS_OVL_CAP_SCALE, + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, }; static const enum omap_overlay_caps omap3430_dss_overlay_caps[] = { /* OMAP_DSS_GFX */ - OMAP_DSS_OVL_CAP_GLOBAL_ALPHA, + OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO1 */ - OMAP_DSS_OVL_CAP_SCALE, + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO2 */ - OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA, + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | + OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, }; static const enum omap_overlay_caps omap3630_dss_overlay_caps[] = { /* OMAP_DSS_GFX */ - OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA, + OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | + OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO1 */ - OMAP_DSS_OVL_CAP_SCALE, + OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO2 */ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | - OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA, + OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, }; static const enum omap_overlay_caps omap4_dss_overlay_caps[] = { /* OMAP_DSS_GFX */ OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | - OMAP_DSS_OVL_CAP_ZORDER, + OMAP_DSS_OVL_CAP_ZORDER | OMAP_DSS_OVL_CAP_POS | + OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO1 */ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | - OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER, + OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER | + OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO2 */ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | - OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER, + OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER | + OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, /* OMAP_DSS_VIDEO3 */ OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | - OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER, + OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER | + OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, }; static const char * const omap2_dss_clk_source_names[] = { @@ -298,6 +407,14 @@ static const char * const omap4_dss_clk_source_names[] = { [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "PLL2_CLK2", }; +static const char * const omap5_dss_clk_source_names[] = { + [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DPLL_DSI1_A_CLK1", + [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DPLL_DSI1_A_CLK2", + [OMAP_DSS_CLK_SRC_FCK] = "DSS_CLK", + [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DPLL_DSI1_C_CLK1", + [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DPLL_DSI1_C_CLK2", +}; + static const struct dss_param_range omap2_dss_param_range[] = { [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, [FEAT_PARAM_DSS_PCD] = { 2, 255 }, @@ -326,6 +443,7 @@ static const struct dss_param_range omap3_dss_param_range[] = { [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 }, [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 }, [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, + [FEAT_PARAM_DSI_FCK] = { 0, 173000000 }, [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, @@ -341,6 +459,23 @@ static const struct dss_param_range omap4_dss_param_range[] = { [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, + [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, + [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, + [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, + [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, + [FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 }, +}; + +static const struct dss_param_range omap5_dss_param_range[] = { + [FEAT_PARAM_DSS_FCK] = { 0, 200000000 }, + [FEAT_PARAM_DSS_PCD] = { 1, 255 }, + [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 }, + [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 }, + [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 }, + [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, + [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, + [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, + [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, @@ -373,6 +508,26 @@ static const enum dss_feat_id omap3430_dss_feat_list[] = { FEAT_ALPHA_FIXED_ZORDER, FEAT_FIFO_MERGE, FEAT_OMAP3_DSI_FIFO_BUG, + FEAT_DPI_USES_VDDS_DSI, +}; + +static const enum dss_feat_id am35xx_dss_feat_list[] = { + FEAT_LCDENABLEPOL, + FEAT_LCDENABLESIGNAL, + FEAT_PCKFREEENABLE, + FEAT_FUNCGATED, + FEAT_LINEBUFFERSPLIT, + FEAT_ROWREPEATENABLE, + FEAT_RESIZECONF, + FEAT_DSI_PLL_FREQSEL, + FEAT_DSI_REVERSE_TXCLKESC, + FEAT_VENC_REQUIRES_TV_DAC_CLK, + FEAT_CPR, + FEAT_PRELOAD, + FEAT_FIR_COEF_V, + FEAT_ALPHA_FIXED_ZORDER, + FEAT_FIFO_MERGE, + FEAT_OMAP3_DSI_FIFO_BUG, }; static const enum dss_feat_id omap3630_dss_feat_list[] = { @@ -447,6 +602,28 @@ static const enum dss_feat_id omap4_dss_feat_list[] = { FEAT_BURST_2D, }; +static const enum dss_feat_id omap5_dss_feat_list[] = { + FEAT_MGR_LCD2, + FEAT_CORE_CLK_DIV, + FEAT_LCD_CLK_SRC, + FEAT_DSI_DCS_CMD_CONFIG_VC, + FEAT_DSI_VC_OCP_WIDTH, + FEAT_DSI_GNQ, + FEAT_HDMI_CTS_SWMODE, + FEAT_HDMI_AUDIO_USE_MCLK, + FEAT_HANDLE_UV_SEPARATE, + FEAT_ATTR2, + FEAT_CPR, + FEAT_PRELOAD, + FEAT_FIR_COEF_V, + FEAT_ALPHA_FREE_ZORDER, + FEAT_FIFO_MERGE, + FEAT_BURST_2D, + FEAT_DSI_PLL_SELFREQDCO, + FEAT_DSI_PLL_REFSEL, + FEAT_DSI_PHY_DCC, +}; + /* OMAP2 DSS Features */ static const struct omap_dss_features omap2_dss_features = { .reg_fields = omap2_dss_reg_fields, @@ -458,6 +635,7 @@ static const struct omap_dss_features omap2_dss_features = { .num_mgrs = 2, .num_ovls = 3, .supported_displays = omap2_dss_supported_displays, + .supported_outputs = omap2_dss_supported_outputs, .supported_color_modes = omap2_dss_supported_color_modes, .overlay_caps = omap2_dss_overlay_caps, .clksrc_names = omap2_dss_clk_source_names, @@ -478,6 +656,31 @@ static const struct omap_dss_features omap3430_dss_features = { .num_mgrs = 2, .num_ovls = 3, .supported_displays = omap3430_dss_supported_displays, + .supported_outputs = omap3430_dss_supported_outputs, + .supported_color_modes = omap3_dss_supported_color_modes, + .overlay_caps = omap3430_dss_overlay_caps, + .clksrc_names = omap3_dss_clk_source_names, + .dss_params = omap3_dss_param_range, + .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB, + .buffer_size_unit = 1, + .burst_size_unit = 8, +}; + +/* + * AM35xx DSS Features. This is basically OMAP3 DSS Features without the + * vdds_dsi regulator. + */ +static const struct omap_dss_features am35xx_dss_features = { + .reg_fields = omap3_dss_reg_fields, + .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), + + .features = am35xx_dss_feat_list, + .num_features = ARRAY_SIZE(am35xx_dss_feat_list), + + .num_mgrs = 2, + .num_ovls = 3, + .supported_displays = omap3430_dss_supported_displays, + .supported_outputs = omap3430_dss_supported_outputs, .supported_color_modes = omap3_dss_supported_color_modes, .overlay_caps = omap3430_dss_overlay_caps, .clksrc_names = omap3_dss_clk_source_names, @@ -497,6 +700,7 @@ static const struct omap_dss_features omap3630_dss_features = { .num_mgrs = 2, .num_ovls = 3, .supported_displays = omap3630_dss_supported_displays, + .supported_outputs = omap3630_dss_supported_outputs, .supported_color_modes = omap3_dss_supported_color_modes, .overlay_caps = omap3630_dss_overlay_caps, .clksrc_names = omap3_dss_clk_source_names, @@ -517,7 +721,9 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = { .num_mgrs = 3, .num_ovls = 4, + .num_wbs = 1, .supported_displays = omap4_dss_supported_displays, + .supported_outputs = omap4_dss_supported_outputs, .supported_color_modes = omap4_dss_supported_color_modes, .overlay_caps = omap4_dss_overlay_caps, .clksrc_names = omap4_dss_clk_source_names, @@ -537,7 +743,9 @@ static const struct omap_dss_features omap4430_es2_0_1_2_dss_features = { .num_mgrs = 3, .num_ovls = 4, + .num_wbs = 1, .supported_displays = omap4_dss_supported_displays, + .supported_outputs = omap4_dss_supported_outputs, .supported_color_modes = omap4_dss_supported_color_modes, .overlay_caps = omap4_dss_overlay_caps, .clksrc_names = omap4_dss_clk_source_names, @@ -557,7 +765,9 @@ static const struct omap_dss_features omap4_dss_features = { .num_mgrs = 3, .num_ovls = 4, + .num_wbs = 1, .supported_displays = omap4_dss_supported_displays, + .supported_outputs = omap4_dss_supported_outputs, .supported_color_modes = omap4_dss_supported_color_modes, .overlay_caps = omap4_dss_overlay_caps, .clksrc_names = omap4_dss_clk_source_names, @@ -567,6 +777,27 @@ static const struct omap_dss_features omap4_dss_features = { .burst_size_unit = 16, }; +/* OMAP5 DSS Features */ +static const struct omap_dss_features omap5_dss_features = { + .reg_fields = omap5_dss_reg_fields, + .num_reg_fields = ARRAY_SIZE(omap5_dss_reg_fields), + + .features = omap5_dss_feat_list, + .num_features = ARRAY_SIZE(omap5_dss_feat_list), + + .num_mgrs = 3, + .num_ovls = 4, + .supported_displays = omap5_dss_supported_displays, + .supported_outputs = omap5_dss_supported_outputs, + .supported_color_modes = omap4_dss_supported_color_modes, + .overlay_caps = omap4_dss_overlay_caps, + .clksrc_names = omap5_dss_clk_source_names, + .dss_params = omap5_dss_param_range, + .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER, + .buffer_size_unit = 16, + .burst_size_unit = 16, +}; + #if defined(CONFIG_OMAP4_DSS_HDMI) /* HDMI OMAP4 Functions*/ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { @@ -612,6 +843,11 @@ int dss_feat_get_num_ovls(void) return omap_current_dss_features->num_ovls; } +int dss_feat_get_num_wbs(void) +{ + return omap_current_dss_features->num_wbs; +} + unsigned long dss_feat_get_param_min(enum dss_range_param param) { return omap_current_dss_features->dss_params[param].min; @@ -627,6 +863,11 @@ enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel return omap_current_dss_features->supported_displays[channel]; } +enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel) +{ + return omap_current_dss_features->supported_outputs[channel]; +} + enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane) { return omap_current_dss_features->supported_color_modes[plane]; @@ -694,8 +935,13 @@ void dss_features_init(void) omap_current_dss_features = &omap2_dss_features; else if (cpu_is_omap3630()) omap_current_dss_features = &omap3630_dss_features; - else if (cpu_is_omap34xx()) - omap_current_dss_features = &omap3430_dss_features; + else if (cpu_is_omap34xx()) { + if (soc_is_am35xx()) { + omap_current_dss_features = &am35xx_dss_features; + } else { + omap_current_dss_features = &omap3430_dss_features; + } + } else if (omap_rev() == OMAP4430_REV_ES1_0) omap_current_dss_features = &omap4430_es1_0_dss_features; else if (omap_rev() == OMAP4430_REV_ES2_0 || @@ -704,6 +950,8 @@ void dss_features_init(void) omap_current_dss_features = &omap4430_es2_0_1_2_dss_features; else if (cpu_is_omap44xx()) omap_current_dss_features = &omap4_dss_features; + else if (soc_is_omap54xx()) + omap_current_dss_features = &omap5_dss_features; else DSSWARN("Unsupported OMAP version"); } diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 996ffcbfed58..9218113b5e88 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -50,6 +50,7 @@ enum dss_feat_id { FEAT_DSI_VC_OCP_WIDTH, FEAT_DSI_REVERSE_TXCLKESC, FEAT_DSI_GNQ, + FEAT_DPI_USES_VDDS_DSI, FEAT_HDMI_CTS_SWMODE, FEAT_HDMI_AUDIO_USE_MCLK, FEAT_HANDLE_UV_SEPARATE, @@ -64,6 +65,9 @@ enum dss_feat_id { /* An unknown HW bug causing the normal FIFO thresholds not to work */ FEAT_OMAP3_DSI_FIFO_BUG, FEAT_BURST_2D, + FEAT_DSI_PLL_SELFREQDCO, + FEAT_DSI_PLL_REFSEL, + FEAT_DSI_PHY_DCC, }; /* DSS register field id */ @@ -91,6 +95,7 @@ enum dss_range_param { FEAT_PARAM_DSIPLL_REGM_DSI, FEAT_PARAM_DSIPLL_FINT, FEAT_PARAM_DSIPLL_LPDIV, + FEAT_PARAM_DSI_FCK, FEAT_PARAM_DOWNSCALE, FEAT_PARAM_LINEWIDTH, FEAT_PARAM_MGR_WIDTH, @@ -100,9 +105,11 @@ enum dss_range_param { /* DSS Feature Functions */ int dss_feat_get_num_mgrs(void); int dss_feat_get_num_ovls(void); +int dss_feat_get_num_wbs(void); unsigned long dss_feat_get_param_min(enum dss_range_param param); unsigned long dss_feat_get_param_max(enum dss_range_param param); enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel); +enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel); enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane); enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane); bool dss_feat_color_mode_supported(enum omap_plane plane, diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 060216fdc578..a48a7dd75b33 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -32,6 +32,8 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/clk.h> +#include <linux/gpio.h> +#include <linux/regulator/consumer.h> #include <video/omapdss.h> #include "ti_hdmi.h" @@ -61,6 +63,13 @@ static struct { struct hdmi_ip_data ip_data; struct clk *sys_clk; + struct regulator *vdda_hdmi_dac_reg; + + int ct_cp_hpd_gpio; + int ls_oe_gpio; + int hpd_gpio; + + struct omap_dss_output output; } hdmi; /* @@ -314,12 +323,47 @@ static void hdmi_runtime_put(void) static int __init hdmi_init_display(struct omap_dss_device *dssdev) { + int r; + + struct gpio gpios[] = { + { hdmi.ct_cp_hpd_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ct_cp_hpd" }, + { hdmi.ls_oe_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ls_oe" }, + { hdmi.hpd_gpio, GPIOF_DIR_IN, "hdmi_hpd" }, + }; + DSSDBG("init_display\n"); dss_init_hdmi_ip_ops(&hdmi.ip_data); + + if (hdmi.vdda_hdmi_dac_reg == NULL) { + struct regulator *reg; + + reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac"); + + if (IS_ERR(reg)) { + DSSERR("can't get VDDA_HDMI_DAC regulator\n"); + return PTR_ERR(reg); + } + + hdmi.vdda_hdmi_dac_reg = reg; + } + + r = gpio_request_array(gpios, ARRAY_SIZE(gpios)); + if (r) + return r; + return 0; } +static void __exit hdmi_uninit_display(struct omap_dss_device *dssdev) +{ + DSSDBG("uninit_display\n"); + + gpio_free(hdmi.ct_cp_hpd_gpio); + gpio_free(hdmi.ls_oe_gpio); + gpio_free(hdmi.hpd_gpio); +} + static const struct hdmi_config *hdmi_find_timing( const struct hdmi_config *timings_arr, int len) @@ -459,32 +503,30 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, static int hdmi_power_on(struct omap_dss_device *dssdev) { int r; - const struct hdmi_config *timing; struct omap_video_timings *p; + struct omap_overlay_manager *mgr = dssdev->output->manager; unsigned long phy; + gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); + gpio_set_value(hdmi.ls_oe_gpio, 1); + + /* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */ + udelay(300); + + r = regulator_enable(hdmi.vdda_hdmi_dac_reg); + if (r) + goto err_vdac_enable; + r = hdmi_runtime_get(); if (r) - return r; + goto err_runtime_get; - dss_mgr_disable(dssdev->manager); + dss_mgr_disable(mgr); - p = &dssdev->panel.timings; + p = &hdmi.ip_data.cfg.timings; - DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", - dssdev->panel.timings.x_res, - dssdev->panel.timings.y_res); + DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); - timing = hdmi_get_timings(); - if (timing == NULL) { - /* HDMI code 4 corresponds to 640 * 480 VGA */ - hdmi.ip_data.cfg.cm.code = 4; - /* DVI mode 1 corresponds to HDMI 0 to DVI */ - hdmi.ip_data.cfg.cm.mode = HDMI_DVI; - hdmi.ip_data.cfg = vesa_timings[0]; - } else { - hdmi.ip_data.cfg = *timing; - } phy = p->pixel_clock; hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data); @@ -495,13 +537,13 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data); if (r) { DSSDBG("Failed to lock PLL\n"); - goto err; + goto err_pll_enable; } r = hdmi.ip_data.ops->phy_enable(&hdmi.ip_data); if (r) { DSSDBG("Failed to start PHY\n"); - goto err; + goto err_phy_enable; } hdmi.ip_data.ops->video_configure(&hdmi.ip_data); @@ -521,13 +563,13 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) dispc_enable_gamma_table(0); /* tv size */ - dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); + dss_mgr_set_timings(mgr, p); r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data); if (r) goto err_vid_enable; - r = dss_mgr_enable(dssdev->manager); + r = dss_mgr_enable(mgr); if (r) goto err_mgr_enable; @@ -537,20 +579,33 @@ err_mgr_enable: hdmi.ip_data.ops->video_disable(&hdmi.ip_data); err_vid_enable: hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); +err_phy_enable: hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); -err: +err_pll_enable: hdmi_runtime_put(); +err_runtime_get: + regulator_disable(hdmi.vdda_hdmi_dac_reg); +err_vdac_enable: + gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); + gpio_set_value(hdmi.ls_oe_gpio, 0); return -EIO; } static void hdmi_power_off(struct omap_dss_device *dssdev) { - dss_mgr_disable(dssdev->manager); + struct omap_overlay_manager *mgr = dssdev->output->manager; + + dss_mgr_disable(mgr); hdmi.ip_data.ops->video_disable(&hdmi.ip_data); hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); hdmi_runtime_put(); + + regulator_disable(hdmi.vdda_hdmi_dac_reg); + + gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); + gpio_set_value(hdmi.ls_oe_gpio, 0); } int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, @@ -567,25 +622,22 @@ int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, } -void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev) +void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) { struct hdmi_cm cm; + const struct hdmi_config *t; - cm = hdmi_get_code(&dssdev->panel.timings); - hdmi.ip_data.cfg.cm.code = cm.code; - hdmi.ip_data.cfg.cm.mode = cm.mode; + mutex_lock(&hdmi.lock); - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - int r; + cm = hdmi_get_code(timings); + hdmi.ip_data.cfg.cm = cm; - hdmi_power_off(dssdev); + t = hdmi_get_timings(); + if (t != NULL) + hdmi.ip_data.cfg = *t; - r = hdmi_power_on(dssdev); - if (r) - DSSERR("failed to power on device\n"); - } else { - dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); - } + mutex_unlock(&hdmi.lock); } static void hdmi_dump_regs(struct seq_file *s) @@ -640,20 +692,20 @@ bool omapdss_hdmi_detect(void) int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_hdmi_data *priv = dssdev->data; + struct omap_dss_output *out = dssdev->output; int r = 0; DSSDBG("ENTER hdmi_display_enable\n"); mutex_lock(&hdmi.lock); - if (dssdev->manager == NULL) { - DSSERR("failed to enable display: no manager\n"); + if (out == NULL || out->manager == NULL) { + DSSERR("failed to enable display: no output/manager\n"); r = -ENODEV; goto err0; } - hdmi.ip_data.hpd_gpio = priv->hpd_gpio; + hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio; r = omap_dss_start_device(dssdev); if (r) { @@ -661,26 +713,15 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) goto err0; } - if (dssdev->platform_enable) { - r = dssdev->platform_enable(dssdev); - if (r) { - DSSERR("failed to enable GPIO's\n"); - goto err1; - } - } - r = hdmi_power_on(dssdev); if (r) { DSSERR("failed to power on device\n"); - goto err2; + goto err1; } mutex_unlock(&hdmi.lock); return 0; -err2: - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); err1: omap_dss_stop_device(dssdev); err0: @@ -696,9 +737,6 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) hdmi_power_off(dssdev); - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - omap_dss_stop_device(dssdev); mutex_unlock(&hdmi.lock); @@ -869,10 +907,14 @@ int hdmi_audio_config(struct omap_dss_audio *audio) #endif -static void __init hdmi_probe_pdata(struct platform_device *pdev) +static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - int r, i; + const char *def_disp_name = dss_get_default_display_name(); + struct omap_dss_device *def_dssdev; + int i; + + def_dssdev = NULL; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -880,17 +922,76 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev) if (dssdev->type != OMAP_DISPLAY_TYPE_HDMI) continue; - r = hdmi_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - continue; + if (def_dssdev == NULL) + def_dssdev = dssdev; + + if (def_disp_name != NULL && + strcmp(dssdev->name, def_disp_name) == 0) { + def_dssdev = dssdev; + break; } + } - r = omap_dss_register_device(dssdev, &pdev->dev, i); - if (r) - DSSERR("device %s register failed: %d\n", - dssdev->name, r); + return def_dssdev; +} + +static void __init hdmi_probe_pdata(struct platform_device *pdev) +{ + struct omap_dss_device *plat_dssdev; + struct omap_dss_device *dssdev; + struct omap_dss_hdmi_data *priv; + int r; + + plat_dssdev = hdmi_find_dssdev(pdev); + + if (!plat_dssdev) + return; + + dssdev = dss_alloc_and_init_device(&pdev->dev); + if (!dssdev) + return; + + dss_copy_device_pdata(dssdev, plat_dssdev); + + priv = dssdev->data; + + hdmi.ct_cp_hpd_gpio = priv->ct_cp_hpd_gpio; + hdmi.ls_oe_gpio = priv->ls_oe_gpio; + hdmi.hpd_gpio = priv->hpd_gpio; + + dssdev->channel = OMAP_DSS_CHANNEL_DIGIT; + + r = hdmi_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; } + + r = dss_add_device(dssdev); + if (r) { + DSSERR("device %s register failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; + } +} + +static void __init hdmi_init_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &hdmi.output; + + out->pdev = pdev; + out->id = OMAP_DSS_OUTPUT_HDMI; + out->type = OMAP_DISPLAY_TYPE_HDMI; + + dss_register_output(out); +} + +static void __exit hdmi_uninit_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &hdmi.output; + + dss_unregister_output(out); } /* HDMI HW IP initialisation */ @@ -929,23 +1030,37 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) hdmi.ip_data.core_av_offset = HDMI_CORE_AV; hdmi.ip_data.pll_offset = HDMI_PLLCTRL; hdmi.ip_data.phy_offset = HDMI_PHY; + mutex_init(&hdmi.ip_data.lock); hdmi_panel_init(); dss_debugfs_create_file("hdmi", hdmi_dump_regs); + hdmi_init_output(pdev); + hdmi_probe_pdata(pdev); return 0; } +static int __exit hdmi_remove_child(struct device *dev, void *data) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + hdmi_uninit_display(dssdev); + return 0; +} + static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) { - omap_dss_unregister_child_devices(&pdev->dev); + device_for_each_child(&pdev->dev, NULL, hdmi_remove_child); + + dss_unregister_child_devices(&pdev->dev); hdmi_panel_exit(); + hdmi_uninit_output(pdev); + pm_runtime_disable(&pdev->dev); hdmi_put_clocks(); diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c index e10844faadf9..69fb115bab32 100644 --- a/drivers/video/omap2/dss/hdmi_panel.c +++ b/drivers/video/omap2/dss/hdmi_panel.c @@ -41,17 +41,34 @@ static struct { static int hdmi_panel_probe(struct omap_dss_device *dssdev) { + /* Initialize default timings to VGA in DVI mode */ + const struct omap_video_timings default_timings = { + .x_res = 640, + .y_res = 480, + .pixel_clock = 25175, + .hsw = 96, + .hfp = 16, + .hbp = 48, + .vsw = 2, + .vfp = 11, + .vbp = 31, + + .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, + .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, + + .interlace = false, + }; + DSSDBG("ENTER hdmi_panel_probe\n"); - dssdev->panel.timings = (struct omap_video_timings) - { 640, 480, 25175, 96, 16, 48, 2, 11, 31, - OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, - false, - }; + dssdev->panel.timings = default_timings; DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n", dssdev->panel.timings.x_res, dssdev->panel.timings.y_res); + + omapdss_hdmi_display_set_timing(dssdev, &dssdev->panel.timings); + return 0; } @@ -228,6 +245,8 @@ static int hdmi_panel_enable(struct omap_dss_device *dssdev) goto err; } + omapdss_hdmi_display_set_timing(dssdev, &dssdev->panel.timings); + r = omapdss_hdmi_display_enable(dssdev); if (r) { DSSERR("failed to power on\n"); @@ -336,8 +355,8 @@ static void hdmi_set_timings(struct omap_dss_device *dssdev, */ hdmi_panel_audio_disable(dssdev); + omapdss_hdmi_display_set_timing(dssdev, timings); dssdev->panel.timings = *timings; - omapdss_hdmi_display_set_timing(dssdev); mutex_unlock(&hdmi.lock); } diff --git a/drivers/video/omap2/dss/manager-sysfs.c b/drivers/video/omap2/dss/manager-sysfs.c new file mode 100644 index 000000000000..9a2fb59b6f89 --- /dev/null +++ b/drivers/video/omap2/dss/manager-sysfs.c @@ -0,0 +1,512 @@ +/* + * Copyright (C) 2009 Nokia Corporation + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * + * Some code and ideas taken from drivers/video/omap/ driver + * by Imre Deak. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define DSS_SUBSYS_NAME "MANAGER" + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/jiffies.h> + +#include <video/omapdss.h> + +#include "dss.h" +#include "dss_features.h" + +static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name); +} + +static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf) +{ + struct omap_dss_device *dssdev = mgr->get_device(mgr); + + return snprintf(buf, PAGE_SIZE, "%s\n", dssdev ? + dssdev->name : "<none>"); +} + +static ssize_t manager_display_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + int r = 0; + size_t len = size; + struct omap_dss_device *dssdev = NULL; + + int match(struct omap_dss_device *dssdev, void *data) + { + const char *str = data; + return sysfs_streq(dssdev->name, str); + } + + if (buf[size-1] == '\n') + --len; + + if (len > 0) + dssdev = omap_dss_find_device((void *)buf, match); + + if (len > 0 && dssdev == NULL) + return -EINVAL; + + if (dssdev) + DSSDBG("display %s found\n", dssdev->name); + + if (mgr->output) { + r = mgr->unset_output(mgr); + if (r) { + DSSERR("failed to unset current output\n"); + goto put_device; + } + } + + if (dssdev) { + struct omap_dss_output *out = dssdev->output; + + /* + * a registered device should have an output connected to it + * already + */ + if (!out) { + DSSERR("device has no output connected to it\n"); + goto put_device; + } + + r = mgr->set_output(mgr, out); + if (r) { + DSSERR("failed to set manager output\n"); + goto put_device; + } + + r = mgr->apply(mgr); + if (r) { + DSSERR("failed to apply dispc config\n"); + goto put_device; + } + } + +put_device: + if (dssdev) + omap_dss_put_device(dssdev); + + return r ? r : size; +} + +static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, + char *buf) +{ + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color); +} + +static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + struct omap_overlay_manager_info info; + u32 color; + int r; + + r = kstrtouint(buf, 0, &color); + if (r) + return r; + + mgr->get_manager_info(mgr, &info); + + info.default_color = color; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +static const char *trans_key_type_str[] = { + "gfx-destination", + "video-source", +}; + +static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr, + char *buf) +{ + enum omap_dss_trans_key_type key_type; + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + key_type = info.trans_key_type; + BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); + + return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); +} + +static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + enum omap_dss_trans_key_type key_type; + struct omap_overlay_manager_info info; + int r; + + for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST; + key_type < ARRAY_SIZE(trans_key_type_str); key_type++) { + if (sysfs_streq(buf, trans_key_type_str[key_type])) + break; + } + + if (key_type == ARRAY_SIZE(trans_key_type_str)) + return -EINVAL; + + mgr->get_manager_info(mgr, &info); + + info.trans_key_type = key_type; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, + char *buf) +{ + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key); +} + +static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + struct omap_overlay_manager_info info; + u32 key_value; + int r; + + r = kstrtouint(buf, 0, &key_value); + if (r) + return r; + + mgr->get_manager_info(mgr, &info); + + info.trans_key = key_value; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, + char *buf) +{ + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled); +} + +static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + struct omap_overlay_manager_info info; + bool enable; + int r; + + r = strtobool(buf, &enable); + if (r) + return r; + + mgr->get_manager_info(mgr, &info); + + info.trans_enabled = enable; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +static ssize_t manager_alpha_blending_enabled_show( + struct omap_overlay_manager *mgr, char *buf) +{ + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); + + return snprintf(buf, PAGE_SIZE, "%d\n", + info.partial_alpha_enabled); +} + +static ssize_t manager_alpha_blending_enabled_store( + struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + struct omap_overlay_manager_info info; + bool enable; + int r; + + WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); + + r = strtobool(buf, &enable); + if (r) + return r; + + mgr->get_manager_info(mgr, &info); + + info.partial_alpha_enabled = enable; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, + char *buf) +{ + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable); +} + +static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + struct omap_overlay_manager_info info; + int r; + bool enable; + + if (!dss_has_feature(FEAT_CPR)) + return -ENODEV; + + r = strtobool(buf, &enable); + if (r) + return r; + + mgr->get_manager_info(mgr, &info); + + if (info.cpr_enable == enable) + return size; + + info.cpr_enable = enable; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr, + char *buf) +{ + struct omap_overlay_manager_info info; + + mgr->get_manager_info(mgr, &info); + + return snprintf(buf, PAGE_SIZE, + "%d %d %d %d %d %d %d %d %d\n", + info.cpr_coefs.rr, + info.cpr_coefs.rg, + info.cpr_coefs.rb, + info.cpr_coefs.gr, + info.cpr_coefs.gg, + info.cpr_coefs.gb, + info.cpr_coefs.br, + info.cpr_coefs.bg, + info.cpr_coefs.bb); +} + +static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr, + const char *buf, size_t size) +{ + struct omap_overlay_manager_info info; + struct omap_dss_cpr_coefs coefs; + int r, i; + s16 *arr; + + if (!dss_has_feature(FEAT_CPR)) + return -ENODEV; + + if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd", + &coefs.rr, &coefs.rg, &coefs.rb, + &coefs.gr, &coefs.gg, &coefs.gb, + &coefs.br, &coefs.bg, &coefs.bb) != 9) + return -EINVAL; + + arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb, + coefs.gr, coefs.gg, coefs.gb, + coefs.br, coefs.bg, coefs.bb }; + + for (i = 0; i < 9; ++i) { + if (arr[i] < -512 || arr[i] > 511) + return -EINVAL; + } + + mgr->get_manager_info(mgr, &info); + + info.cpr_coefs = coefs; + + r = mgr->set_manager_info(mgr, &info); + if (r) + return r; + + r = mgr->apply(mgr); + if (r) + return r; + + return size; +} + +struct manager_attribute { + struct attribute attr; + ssize_t (*show)(struct omap_overlay_manager *, char *); + ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t); +}; + +#define MANAGER_ATTR(_name, _mode, _show, _store) \ + struct manager_attribute manager_attr_##_name = \ + __ATTR(_name, _mode, _show, _store) + +static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL); +static MANAGER_ATTR(display, S_IRUGO|S_IWUSR, + manager_display_show, manager_display_store); +static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR, + manager_default_color_show, manager_default_color_store); +static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR, + manager_trans_key_type_show, manager_trans_key_type_store); +static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR, + manager_trans_key_value_show, manager_trans_key_value_store); +static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR, + manager_trans_key_enabled_show, + manager_trans_key_enabled_store); +static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR, + manager_alpha_blending_enabled_show, + manager_alpha_blending_enabled_store); +static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR, + manager_cpr_enable_show, + manager_cpr_enable_store); +static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR, + manager_cpr_coef_show, + manager_cpr_coef_store); + + +static struct attribute *manager_sysfs_attrs[] = { + &manager_attr_name.attr, + &manager_attr_display.attr, + &manager_attr_default_color.attr, + &manager_attr_trans_key_type.attr, + &manager_attr_trans_key_value.attr, + &manager_attr_trans_key_enabled.attr, + &manager_attr_alpha_blending_enabled.attr, + &manager_attr_cpr_enable.attr, + &manager_attr_cpr_coef.attr, + NULL +}; + +static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct omap_overlay_manager *manager; + struct manager_attribute *manager_attr; + + manager = container_of(kobj, struct omap_overlay_manager, kobj); + manager_attr = container_of(attr, struct manager_attribute, attr); + + if (!manager_attr->show) + return -ENOENT; + + return manager_attr->show(manager, buf); +} + +static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t size) +{ + struct omap_overlay_manager *manager; + struct manager_attribute *manager_attr; + + manager = container_of(kobj, struct omap_overlay_manager, kobj); + manager_attr = container_of(attr, struct manager_attribute, attr); + + if (!manager_attr->store) + return -ENOENT; + + return manager_attr->store(manager, buf, size); +} + +static const struct sysfs_ops manager_sysfs_ops = { + .show = manager_attr_show, + .store = manager_attr_store, +}; + +static struct kobj_type manager_ktype = { + .sysfs_ops = &manager_sysfs_ops, + .default_attrs = manager_sysfs_attrs, +}; + +int dss_manager_kobj_init(struct omap_overlay_manager *mgr, + struct platform_device *pdev) +{ + return kobject_init_and_add(&mgr->kobj, &manager_ktype, + &pdev->dev.kobj, "manager%d", mgr->id); +} + +void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr) +{ + kobject_del(&mgr->kobj); + kobject_put(&mgr->kobj); +} diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 53710fadc82d..c54d2f620ce3 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -36,463 +36,15 @@ static int num_managers; static struct omap_overlay_manager *managers; -static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) +static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr) { - return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name); + return mgr->output ? mgr->output->device : NULL; } -static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", - mgr->device ? mgr->device->name : "<none>"); -} - -static ssize_t manager_display_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - int r = 0; - size_t len = size; - struct omap_dss_device *dssdev = NULL; - - int match(struct omap_dss_device *dssdev, void *data) - { - const char *str = data; - return sysfs_streq(dssdev->name, str); - } - - if (buf[size-1] == '\n') - --len; - - if (len > 0) - dssdev = omap_dss_find_device((void *)buf, match); - - if (len > 0 && dssdev == NULL) - return -EINVAL; - - if (dssdev) - DSSDBG("display %s found\n", dssdev->name); - - if (mgr->device) { - r = mgr->unset_device(mgr); - if (r) { - DSSERR("failed to unset display\n"); - goto put_device; - } - } - - if (dssdev) { - r = mgr->set_device(mgr, dssdev); - if (r) { - DSSERR("failed to set manager\n"); - goto put_device; - } - - r = mgr->apply(mgr); - if (r) { - DSSERR("failed to apply dispc config\n"); - goto put_device; - } - } - -put_device: - if (dssdev) - omap_dss_put_device(dssdev); - - return r ? r : size; -} - -static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color); -} - -static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - u32 color; - int r; - - r = kstrtouint(buf, 0, &color); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - info.default_color = color; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static const char *trans_key_type_str[] = { - "gfx-destination", - "video-source", -}; - -static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr, - char *buf) -{ - enum omap_dss_trans_key_type key_type; - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - key_type = info.trans_key_type; - BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); - - return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); -} - -static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - enum omap_dss_trans_key_type key_type; - struct omap_overlay_manager_info info; - int r; - - for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST; - key_type < ARRAY_SIZE(trans_key_type_str); key_type++) { - if (sysfs_streq(buf, trans_key_type_str[key_type])) - break; - } - - if (key_type == ARRAY_SIZE(trans_key_type_str)) - return -EINVAL; - - mgr->get_manager_info(mgr, &info); - - info.trans_key_type = key_type; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key); -} - -static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - u32 key_value; - int r; - - r = kstrtouint(buf, 0, &key_value); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - info.trans_key = key_value; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled); -} - -static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - bool enable; - int r; - - r = strtobool(buf, &enable); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - info.trans_enabled = enable; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_alpha_blending_enabled_show( - struct omap_overlay_manager *mgr, char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); - - return snprintf(buf, PAGE_SIZE, "%d\n", - info.partial_alpha_enabled); -} - -static ssize_t manager_alpha_blending_enabled_store( - struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - bool enable; - int r; - - WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); - - r = strtobool(buf, &enable); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - info.partial_alpha_enabled = enable; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable); -} - -static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - int r; - bool enable; - - if (!dss_has_feature(FEAT_CPR)) - return -ENODEV; - - r = strtobool(buf, &enable); - if (r) - return r; - - mgr->get_manager_info(mgr, &info); - - if (info.cpr_enable == enable) - return size; - - info.cpr_enable = enable; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr, - char *buf) -{ - struct omap_overlay_manager_info info; - - mgr->get_manager_info(mgr, &info); - - return snprintf(buf, PAGE_SIZE, - "%d %d %d %d %d %d %d %d %d\n", - info.cpr_coefs.rr, - info.cpr_coefs.rg, - info.cpr_coefs.rb, - info.cpr_coefs.gr, - info.cpr_coefs.gg, - info.cpr_coefs.gb, - info.cpr_coefs.br, - info.cpr_coefs.bg, - info.cpr_coefs.bb); -} - -static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr, - const char *buf, size_t size) -{ - struct omap_overlay_manager_info info; - struct omap_dss_cpr_coefs coefs; - int r, i; - s16 *arr; - - if (!dss_has_feature(FEAT_CPR)) - return -ENODEV; - - if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd", - &coefs.rr, &coefs.rg, &coefs.rb, - &coefs.gr, &coefs.gg, &coefs.gb, - &coefs.br, &coefs.bg, &coefs.bb) != 9) - return -EINVAL; - - arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb, - coefs.gr, coefs.gg, coefs.gb, - coefs.br, coefs.bg, coefs.bb }; - - for (i = 0; i < 9; ++i) { - if (arr[i] < -512 || arr[i] > 511) - return -EINVAL; - } - - mgr->get_manager_info(mgr, &info); - - info.cpr_coefs = coefs; - - r = mgr->set_manager_info(mgr, &info); - if (r) - return r; - - r = mgr->apply(mgr); - if (r) - return r; - - return size; -} - -struct manager_attribute { - struct attribute attr; - ssize_t (*show)(struct omap_overlay_manager *, char *); - ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t); -}; - -#define MANAGER_ATTR(_name, _mode, _show, _store) \ - struct manager_attribute manager_attr_##_name = \ - __ATTR(_name, _mode, _show, _store) - -static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL); -static MANAGER_ATTR(display, S_IRUGO|S_IWUSR, - manager_display_show, manager_display_store); -static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR, - manager_default_color_show, manager_default_color_store); -static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR, - manager_trans_key_type_show, manager_trans_key_type_store); -static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR, - manager_trans_key_value_show, manager_trans_key_value_store); -static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR, - manager_trans_key_enabled_show, - manager_trans_key_enabled_store); -static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR, - manager_alpha_blending_enabled_show, - manager_alpha_blending_enabled_store); -static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR, - manager_cpr_enable_show, - manager_cpr_enable_store); -static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR, - manager_cpr_coef_show, - manager_cpr_coef_store); - - -static struct attribute *manager_sysfs_attrs[] = { - &manager_attr_name.attr, - &manager_attr_display.attr, - &manager_attr_default_color.attr, - &manager_attr_trans_key_type.attr, - &manager_attr_trans_key_value.attr, - &manager_attr_trans_key_enabled.attr, - &manager_attr_alpha_blending_enabled.attr, - &manager_attr_cpr_enable.attr, - &manager_attr_cpr_coef.attr, - NULL -}; - -static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct omap_overlay_manager *manager; - struct manager_attribute *manager_attr; - - manager = container_of(kobj, struct omap_overlay_manager, kobj); - manager_attr = container_of(attr, struct manager_attribute, attr); - - if (!manager_attr->show) - return -ENOENT; - - return manager_attr->show(manager, buf); -} - -static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t size) -{ - struct omap_overlay_manager *manager; - struct manager_attribute *manager_attr; - - manager = container_of(kobj, struct omap_overlay_manager, kobj); - manager_attr = container_of(attr, struct manager_attribute, attr); - - if (!manager_attr->store) - return -ENOENT; - - return manager_attr->store(manager, buf, size); -} - -static const struct sysfs_ops manager_sysfs_ops = { - .show = manager_attr_show, - .store = manager_attr_store, -}; - -static struct kobj_type manager_ktype = { - .sysfs_ops = &manager_sysfs_ops, - .default_attrs = manager_sysfs_attrs, -}; - static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) { unsigned long timeout = msecs_to_jiffies(500); + struct omap_dss_device *dssdev = mgr->get_device(mgr); u32 irq; int r; @@ -500,9 +52,9 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) if (r) return r; - if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) + if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) irq = DISPC_IRQ_EVSYNC_ODD; - else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI) + else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI) irq = DISPC_IRQ_EVSYNC_EVEN; else irq = dispc_mgr_get_vsync_irq(mgr->id); @@ -547,23 +99,24 @@ int dss_init_overlay_managers(struct platform_device *pdev) break; } - mgr->set_device = &dss_mgr_set_device; - mgr->unset_device = &dss_mgr_unset_device; + mgr->set_output = &dss_mgr_set_output; + mgr->unset_output = &dss_mgr_unset_output; mgr->apply = &omap_dss_mgr_apply; mgr->set_manager_info = &dss_mgr_set_info; mgr->get_manager_info = &dss_mgr_get_info; mgr->wait_for_go = &dss_mgr_wait_for_go; mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; + mgr->get_device = &dss_mgr_get_device; mgr->caps = 0; mgr->supported_displays = dss_feat_get_supported_displays(mgr->id); + mgr->supported_outputs = + dss_feat_get_supported_outputs(mgr->id); INIT_LIST_HEAD(&mgr->overlays); - r = kobject_init_and_add(&mgr->kobj, &manager_ktype, - &pdev->dev.kobj, "manager%d", i); - + r = dss_manager_kobj_init(mgr, pdev); if (r) DSSERR("failed to create sysfs file\n"); } @@ -577,9 +130,7 @@ void dss_uninit_overlay_managers(struct platform_device *pdev) for (i = 0; i < num_managers; ++i) { struct omap_overlay_manager *mgr = &managers[i]; - - kobject_del(&mgr->kobj); - kobject_put(&mgr->kobj); + dss_manager_kobj_uninit(mgr); } kfree(managers); diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c new file mode 100644 index 000000000000..813f26682b7a --- /dev/null +++ b/drivers/video/omap2/dss/output.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2012 Texas Instruments Ltd + * Author: Archit Taneja <archit@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <video/omapdss.h> + +#include "dss.h" + +static LIST_HEAD(output_list); +static DEFINE_MUTEX(output_lock); + +int omapdss_output_set_device(struct omap_dss_output *out, + struct omap_dss_device *dssdev) +{ + int r; + + mutex_lock(&output_lock); + + if (out->device) { + DSSERR("output already has device %s connected to it\n", + out->device->name); + r = -EINVAL; + goto err; + } + + if (out->type != dssdev->type) { + DSSERR("output type and display type don't match\n"); + r = -EINVAL; + goto err; + } + + out->device = dssdev; + dssdev->output = out; + + mutex_unlock(&output_lock); + + return 0; +err: + mutex_unlock(&output_lock); + + return r; +} +EXPORT_SYMBOL(omapdss_output_set_device); + +int omapdss_output_unset_device(struct omap_dss_output *out) +{ + int r; + + mutex_lock(&output_lock); + + if (!out->device) { + DSSERR("output doesn't have a device connected to it\n"); + r = -EINVAL; + goto err; + } + + if (out->device->state != OMAP_DSS_DISPLAY_DISABLED) { + DSSERR("device %s is not disabled, cannot unset device\n", + out->device->name); + r = -EINVAL; + goto err; + } + + out->device->output = NULL; + out->device = NULL; + + mutex_unlock(&output_lock); + + return 0; +err: + mutex_unlock(&output_lock); + + return r; +} +EXPORT_SYMBOL(omapdss_output_unset_device); + +void dss_register_output(struct omap_dss_output *out) +{ + list_add_tail(&out->list, &output_list); +} + +void dss_unregister_output(struct omap_dss_output *out) +{ + list_del(&out->list); +} + +struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id) +{ + struct omap_dss_output *out; + + list_for_each_entry(out, &output_list, list) { + if (out->id == id) + return out; + } + + return NULL; +} + +struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev) +{ + struct omap_dss_output *out = NULL; + enum omap_dss_output_id id; + + switch (dssdev->type) { + case OMAP_DISPLAY_TYPE_DPI: + out = omap_dss_get_output(OMAP_DSS_OUTPUT_DPI); + break; + case OMAP_DISPLAY_TYPE_DBI: + out = omap_dss_get_output(OMAP_DSS_OUTPUT_DBI); + break; + case OMAP_DISPLAY_TYPE_SDI: + out = omap_dss_get_output(OMAP_DSS_OUTPUT_SDI); + break; + case OMAP_DISPLAY_TYPE_VENC: + out = omap_dss_get_output(OMAP_DSS_OUTPUT_VENC); + break; + case OMAP_DISPLAY_TYPE_HDMI: + out = omap_dss_get_output(OMAP_DSS_OUTPUT_HDMI); + break; + case OMAP_DISPLAY_TYPE_DSI: + id = dssdev->phy.dsi.module == 0 ? OMAP_DSS_OUTPUT_DSI1 : + OMAP_DSS_OUTPUT_DSI2; + out = omap_dss_get_output(id); + break; + default: + break; + } + + return out; +} diff --git a/drivers/video/omap2/dss/overlay-sysfs.c b/drivers/video/omap2/dss/overlay-sysfs.c new file mode 100644 index 000000000000..4cc5ddebfb34 --- /dev/null +++ b/drivers/video/omap2/dss/overlay-sysfs.c @@ -0,0 +1,456 @@ +/* + * Copyright (C) 2009 Nokia Corporation + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * + * Some code and ideas taken from drivers/video/omap/ driver + * by Imre Deak. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define DSS_SUBSYS_NAME "OVERLAY" + +#include <linux/module.h> +#include <linux/err.h> +#include <linux/sysfs.h> +#include <linux/kobject.h> +#include <linux/platform_device.h> + +#include <video/omapdss.h> + +#include "dss.h" +#include "dss_features.h" + +static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name); +} + +static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", + ovl->manager ? ovl->manager->name : "<none>"); +} + +static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, + size_t size) +{ + int i, r; + struct omap_overlay_manager *mgr = NULL; + struct omap_overlay_manager *old_mgr; + int len = size; + + if (buf[size-1] == '\n') + --len; + + if (len > 0) { + for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { + mgr = omap_dss_get_overlay_manager(i); + + if (sysfs_streq(buf, mgr->name)) + break; + + mgr = NULL; + } + } + + if (len > 0 && mgr == NULL) + return -EINVAL; + + if (mgr) + DSSDBG("manager %s found\n", mgr->name); + + if (mgr == ovl->manager) + return size; + + old_mgr = ovl->manager; + + r = dispc_runtime_get(); + if (r) + return r; + + /* detach old manager */ + if (old_mgr) { + r = ovl->unset_manager(ovl); + if (r) { + DSSERR("detach failed\n"); + goto err; + } + + r = old_mgr->apply(old_mgr); + if (r) + goto err; + } + + if (mgr) { + r = ovl->set_manager(ovl, mgr); + if (r) { + DSSERR("Failed to attach overlay\n"); + goto err; + } + + r = mgr->apply(mgr); + if (r) + goto err; + } + + dispc_runtime_put(); + + return size; + +err: + dispc_runtime_put(); + return r; +} + +static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d,%d\n", + info.width, info.height); +} + +static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width); +} + +static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d,%d\n", + info.pos_x, info.pos_y); +} + +static ssize_t overlay_position_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + char *last; + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + info.pos_x = simple_strtoul(buf, &last, 10); + ++last; + if (last - buf >= size) + return -EINVAL; + + info.pos_y = simple_strtoul(last, &last, 10); + + r = ovl->set_overlay_info(ovl, &info); + if (r) + return r; + + if (ovl->manager) { + r = ovl->manager->apply(ovl->manager); + if (r) + return r; + } + + return size; +} + +static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d,%d\n", + info.out_width, info.out_height); +} + +static ssize_t overlay_output_size_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + char *last; + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + info.out_width = simple_strtoul(buf, &last, 10); + ++last; + if (last - buf >= size) + return -EINVAL; + + info.out_height = simple_strtoul(last, &last, 10); + + r = ovl->set_overlay_info(ovl, &info); + if (r) + return r; + + if (ovl->manager) { + r = ovl->manager->apply(ovl->manager); + if (r) + return r; + } + + return size; +} + +static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl)); +} + +static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, + size_t size) +{ + int r; + bool enable; + + r = strtobool(buf, &enable); + if (r) + return r; + + if (enable) + r = ovl->enable(ovl); + else + r = ovl->disable(ovl); + + if (r) + return r; + + return size; +} + +static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", + info.global_alpha); +} + +static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + u8 alpha; + struct omap_overlay_info info; + + if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) + return -ENODEV; + + r = kstrtou8(buf, 0, &alpha); + if (r) + return r; + + ovl->get_overlay_info(ovl, &info); + + info.global_alpha = alpha; + + r = ovl->set_overlay_info(ovl, &info); + if (r) + return r; + + if (ovl->manager) { + r = ovl->manager->apply(ovl->manager); + if (r) + return r; + } + + return size; +} + +static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, + char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", + info.pre_mult_alpha); +} + +static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + u8 alpha; + struct omap_overlay_info info; + + if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) + return -ENODEV; + + r = kstrtou8(buf, 0, &alpha); + if (r) + return r; + + ovl->get_overlay_info(ovl, &info); + + info.pre_mult_alpha = alpha; + + r = ovl->set_overlay_info(ovl, &info); + if (r) + return r; + + if (ovl->manager) { + r = ovl->manager->apply(ovl->manager); + if (r) + return r; + } + + return size; +} + +static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf) +{ + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder); +} + +static ssize_t overlay_zorder_store(struct omap_overlay *ovl, + const char *buf, size_t size) +{ + int r; + u8 zorder; + struct omap_overlay_info info; + + if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) + return -ENODEV; + + r = kstrtou8(buf, 0, &zorder); + if (r) + return r; + + ovl->get_overlay_info(ovl, &info); + + info.zorder = zorder; + + r = ovl->set_overlay_info(ovl, &info); + if (r) + return r; + + if (ovl->manager) { + r = ovl->manager->apply(ovl->manager); + if (r) + return r; + } + + return size; +} + +struct overlay_attribute { + struct attribute attr; + ssize_t (*show)(struct omap_overlay *, char *); + ssize_t (*store)(struct omap_overlay *, const char *, size_t); +}; + +#define OVERLAY_ATTR(_name, _mode, _show, _store) \ + struct overlay_attribute overlay_attr_##_name = \ + __ATTR(_name, _mode, _show, _store) + +static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL); +static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR, + overlay_manager_show, overlay_manager_store); +static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL); +static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL); +static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR, + overlay_position_show, overlay_position_store); +static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR, + overlay_output_size_show, overlay_output_size_store); +static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR, + overlay_enabled_show, overlay_enabled_store); +static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR, + overlay_global_alpha_show, overlay_global_alpha_store); +static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR, + overlay_pre_mult_alpha_show, + overlay_pre_mult_alpha_store); +static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR, + overlay_zorder_show, overlay_zorder_store); + +static struct attribute *overlay_sysfs_attrs[] = { + &overlay_attr_name.attr, + &overlay_attr_manager.attr, + &overlay_attr_input_size.attr, + &overlay_attr_screen_width.attr, + &overlay_attr_position.attr, + &overlay_attr_output_size.attr, + &overlay_attr_enabled.attr, + &overlay_attr_global_alpha.attr, + &overlay_attr_pre_mult_alpha.attr, + &overlay_attr_zorder.attr, + NULL +}; + +static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct omap_overlay *overlay; + struct overlay_attribute *overlay_attr; + + overlay = container_of(kobj, struct omap_overlay, kobj); + overlay_attr = container_of(attr, struct overlay_attribute, attr); + + if (!overlay_attr->show) + return -ENOENT; + + return overlay_attr->show(overlay, buf); +} + +static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t size) +{ + struct omap_overlay *overlay; + struct overlay_attribute *overlay_attr; + + overlay = container_of(kobj, struct omap_overlay, kobj); + overlay_attr = container_of(attr, struct overlay_attribute, attr); + + if (!overlay_attr->store) + return -ENOENT; + + return overlay_attr->store(overlay, buf, size); +} + +static const struct sysfs_ops overlay_sysfs_ops = { + .show = overlay_attr_show, + .store = overlay_attr_store, +}; + +static struct kobj_type overlay_ktype = { + .sysfs_ops = &overlay_sysfs_ops, + .default_attrs = overlay_sysfs_attrs, +}; + +int dss_overlay_kobj_init(struct omap_overlay *ovl, + struct platform_device *pdev) +{ + return kobject_init_and_add(&ovl->kobj, &overlay_ktype, + &pdev->dev.kobj, "overlay%d", ovl->id); +} + +void dss_overlay_kobj_uninit(struct omap_overlay *ovl) +{ + kobject_del(&ovl->kobj); + kobject_put(&ovl->kobj); +} diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 952c6fad9a81..45f4994bc6b0 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -26,13 +26,11 @@ #include <linux/module.h> #include <linux/err.h> #include <linux/sysfs.h> -#include <linux/kobject.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/slab.h> #include <video/omapdss.h> -#include <plat/cpu.h> #include "dss.h" #include "dss_features.h" @@ -40,417 +38,13 @@ static int num_overlays; static struct omap_overlay *overlays; -static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) +static inline struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl) { - return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name); + return ovl->manager ? + (ovl->manager->output ? ovl->manager->output->device : NULL) : + NULL; } -static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", - ovl->manager ? ovl->manager->name : "<none>"); -} - -static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, - size_t size) -{ - int i, r; - struct omap_overlay_manager *mgr = NULL; - struct omap_overlay_manager *old_mgr; - int len = size; - - if (buf[size-1] == '\n') - --len; - - if (len > 0) { - for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { - mgr = omap_dss_get_overlay_manager(i); - - if (sysfs_streq(buf, mgr->name)) - break; - - mgr = NULL; - } - } - - if (len > 0 && mgr == NULL) - return -EINVAL; - - if (mgr) - DSSDBG("manager %s found\n", mgr->name); - - if (mgr == ovl->manager) - return size; - - old_mgr = ovl->manager; - - r = dispc_runtime_get(); - if (r) - return r; - - /* detach old manager */ - if (old_mgr) { - r = ovl->unset_manager(ovl); - if (r) { - DSSERR("detach failed\n"); - goto err; - } - - r = old_mgr->apply(old_mgr); - if (r) - goto err; - } - - if (mgr) { - r = ovl->set_manager(ovl, mgr); - if (r) { - DSSERR("Failed to attach overlay\n"); - goto err; - } - - r = mgr->apply(mgr); - if (r) - goto err; - } - - dispc_runtime_put(); - - return size; - -err: - dispc_runtime_put(); - return r; -} - -static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d,%d\n", - info.width, info.height); -} - -static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width); -} - -static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d,%d\n", - info.pos_x, info.pos_y); -} - -static ssize_t overlay_position_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - char *last; - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - info.pos_x = simple_strtoul(buf, &last, 10); - ++last; - if (last - buf >= size) - return -EINVAL; - - info.pos_y = simple_strtoul(last, &last, 10); - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d,%d\n", - info.out_width, info.out_height); -} - -static ssize_t overlay_output_size_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - char *last; - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - info.out_width = simple_strtoul(buf, &last, 10); - ++last; - if (last - buf >= size) - return -EINVAL; - - info.out_height = simple_strtoul(last, &last, 10); - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl)); -} - -static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, - size_t size) -{ - int r; - bool enable; - - r = strtobool(buf, &enable); - if (r) - return r; - - if (enable) - r = ovl->enable(ovl); - else - r = ovl->disable(ovl); - - if (r) - return r; - - return size; -} - -static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", - info.global_alpha); -} - -static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - u8 alpha; - struct omap_overlay_info info; - - if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) - return -ENODEV; - - r = kstrtou8(buf, 0, &alpha); - if (r) - return r; - - ovl->get_overlay_info(ovl, &info); - - info.global_alpha = alpha; - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, - char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", - info.pre_mult_alpha); -} - -static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - u8 alpha; - struct omap_overlay_info info; - - if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) - return -ENODEV; - - r = kstrtou8(buf, 0, &alpha); - if (r) - return r; - - ovl->get_overlay_info(ovl, &info); - - info.pre_mult_alpha = alpha; - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf) -{ - struct omap_overlay_info info; - - ovl->get_overlay_info(ovl, &info); - - return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder); -} - -static ssize_t overlay_zorder_store(struct omap_overlay *ovl, - const char *buf, size_t size) -{ - int r; - u8 zorder; - struct omap_overlay_info info; - - if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) - return -ENODEV; - - r = kstrtou8(buf, 0, &zorder); - if (r) - return r; - - ovl->get_overlay_info(ovl, &info); - - info.zorder = zorder; - - r = ovl->set_overlay_info(ovl, &info); - if (r) - return r; - - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); - if (r) - return r; - } - - return size; -} - -struct overlay_attribute { - struct attribute attr; - ssize_t (*show)(struct omap_overlay *, char *); - ssize_t (*store)(struct omap_overlay *, const char *, size_t); -}; - -#define OVERLAY_ATTR(_name, _mode, _show, _store) \ - struct overlay_attribute overlay_attr_##_name = \ - __ATTR(_name, _mode, _show, _store) - -static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL); -static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR, - overlay_manager_show, overlay_manager_store); -static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL); -static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL); -static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR, - overlay_position_show, overlay_position_store); -static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR, - overlay_output_size_show, overlay_output_size_store); -static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR, - overlay_enabled_show, overlay_enabled_store); -static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR, - overlay_global_alpha_show, overlay_global_alpha_store); -static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR, - overlay_pre_mult_alpha_show, - overlay_pre_mult_alpha_store); -static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR, - overlay_zorder_show, overlay_zorder_store); - -static struct attribute *overlay_sysfs_attrs[] = { - &overlay_attr_name.attr, - &overlay_attr_manager.attr, - &overlay_attr_input_size.attr, - &overlay_attr_screen_width.attr, - &overlay_attr_position.attr, - &overlay_attr_output_size.attr, - &overlay_attr_enabled.attr, - &overlay_attr_global_alpha.attr, - &overlay_attr_pre_mult_alpha.attr, - &overlay_attr_zorder.attr, - NULL -}; - -static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct omap_overlay *overlay; - struct overlay_attribute *overlay_attr; - - overlay = container_of(kobj, struct omap_overlay, kobj); - overlay_attr = container_of(attr, struct overlay_attribute, attr); - - if (!overlay_attr->show) - return -ENOENT; - - return overlay_attr->show(overlay, buf); -} - -static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t size) -{ - struct omap_overlay *overlay; - struct overlay_attribute *overlay_attr; - - overlay = container_of(kobj, struct omap_overlay, kobj); - overlay_attr = container_of(attr, struct overlay_attribute, attr); - - if (!overlay_attr->store) - return -ENOENT; - - return overlay_attr->store(overlay, buf, size); -} - -static const struct sysfs_ops overlay_sysfs_ops = { - .show = overlay_attr_show, - .store = overlay_attr_store, -}; - -static struct kobj_type overlay_ktype = { - .sysfs_ops = &overlay_sysfs_ops, - .default_attrs = overlay_sysfs_attrs, -}; - int omap_dss_get_num_overlays(void) { return num_overlays; @@ -507,97 +101,25 @@ void dss_init_overlays(struct platform_device *pdev) ovl->set_overlay_info = &dss_ovl_set_info; ovl->get_overlay_info = &dss_ovl_get_info; ovl->wait_for_go = &dss_mgr_wait_for_go_ovl; + ovl->get_device = &dss_ovl_get_device; ovl->caps = dss_feat_get_overlay_caps(ovl->id); ovl->supported_modes = dss_feat_get_supported_color_modes(ovl->id); - r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, - &pdev->dev.kobj, "overlay%d", i); - + r = dss_overlay_kobj_init(ovl, pdev); if (r) DSSERR("failed to create sysfs file\n"); } } -/* connect overlays to the new device, if not already connected. if force - * selected, connect always. */ -void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) -{ - int i; - struct omap_overlay_manager *lcd_mgr; - struct omap_overlay_manager *tv_mgr; - struct omap_overlay_manager *lcd2_mgr = NULL; - struct omap_overlay_manager *lcd3_mgr = NULL; - struct omap_overlay_manager *mgr = NULL; - - lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD); - tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_DIGIT); - if (dss_has_feature(FEAT_MGR_LCD3)) - lcd3_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD3); - if (dss_has_feature(FEAT_MGR_LCD2)) - lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_CHANNEL_LCD2); - - if (dssdev->channel == OMAP_DSS_CHANNEL_LCD3) { - if (!lcd3_mgr->device || force) { - if (lcd3_mgr->device) - lcd3_mgr->unset_device(lcd3_mgr); - lcd3_mgr->set_device(lcd3_mgr, dssdev); - mgr = lcd3_mgr; - } - } else if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) { - if (!lcd2_mgr->device || force) { - if (lcd2_mgr->device) - lcd2_mgr->unset_device(lcd2_mgr); - lcd2_mgr->set_device(lcd2_mgr, dssdev); - mgr = lcd2_mgr; - } - } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC - && dssdev->type != OMAP_DISPLAY_TYPE_HDMI) { - if (!lcd_mgr->device || force) { - if (lcd_mgr->device) - lcd_mgr->unset_device(lcd_mgr); - lcd_mgr->set_device(lcd_mgr, dssdev); - mgr = lcd_mgr; - } - } - - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC - || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { - if (!tv_mgr->device || force) { - if (tv_mgr->device) - tv_mgr->unset_device(tv_mgr); - tv_mgr->set_device(tv_mgr, dssdev); - mgr = tv_mgr; - } - } - - if (mgr) { - dispc_runtime_get(); - - for (i = 0; i < dss_feat_get_num_ovls(); i++) { - struct omap_overlay *ovl; - ovl = omap_dss_get_overlay(i); - if (!ovl->manager || force) { - if (ovl->manager) - ovl->unset_manager(ovl); - ovl->set_manager(ovl, mgr); - } - } - - dispc_runtime_put(); - } -} - void dss_uninit_overlays(struct platform_device *pdev) { int i; for (i = 0; i < num_overlays; ++i) { struct omap_overlay *ovl = &overlays[i]; - - kobject_del(&ovl->kobj); - kobject_put(&ovl->kobj); + dss_overlay_kobj_uninit(ovl); } kfree(overlays); diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 7c087424b634..7282e5af3e1a 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -111,6 +111,13 @@ static struct { struct omap_dss_device *dssdev[2]; struct semaphore bus_lock; + + struct omap_video_timings timings; + int pixel_size; + int data_lines; + struct rfbi_timings intf_timings; + + struct omap_dss_output output; } rfbi; static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val) @@ -300,30 +307,23 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width, } EXPORT_SYMBOL(omap_rfbi_write_pixels); -static int rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width, - u16 height, void (*callback)(void *data), void *data) +static int rfbi_transfer_area(struct omap_dss_device *dssdev, + void (*callback)(void *data), void *data) { u32 l; int r; - struct omap_video_timings timings = { - .hsw = 1, - .hfp = 1, - .hbp = 1, - .vsw = 1, - .vfp = 0, - .vbp = 0, - .x_res = width, - .y_res = height, - }; + struct omap_overlay_manager *mgr = dssdev->output->manager; + u16 width = rfbi.timings.x_res; + u16 height = rfbi.timings.y_res; /*BUG_ON(callback == 0);*/ BUG_ON(rfbi.framedone_callback != NULL); DSSDBG("rfbi_transfer_area %dx%d\n", width, height); - dss_mgr_set_timings(dssdev->manager, &timings); + dss_mgr_set_timings(mgr, &rfbi.timings); - r = dss_mgr_enable(dssdev->manager); + r = dss_mgr_enable(mgr); if (r) return r; @@ -770,62 +770,45 @@ static int rfbi_configure(int rfbi_module, int bpp, int lines) return 0; } -int omap_rfbi_configure(struct omap_dss_device *dssdev, int pixel_size, - int data_lines) +int omap_rfbi_configure(struct omap_dss_device *dssdev) { - return rfbi_configure(dssdev->phy.rfbi.channel, pixel_size, data_lines); + return rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size, + rfbi.data_lines); } EXPORT_SYMBOL(omap_rfbi_configure); -int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, - u16 *x, u16 *y, u16 *w, u16 *h) +int omap_rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *), + void *data) { - u16 dw, dh; - struct omap_video_timings timings = { - .hsw = 1, - .hfp = 1, - .hbp = 1, - .vsw = 1, - .vfp = 0, - .vbp = 0, - .x_res = *w, - .y_res = *h, - }; - - dssdev->driver->get_resolution(dssdev, &dw, &dh); - - if (*x > dw || *y > dh) - return -EINVAL; - - if (*x + *w > dw) - return -EINVAL; - - if (*y + *h > dh) - return -EINVAL; - - if (*w == 1) - return -EINVAL; - - if (*w == 0 || *h == 0) - return -EINVAL; - - dss_mgr_set_timings(dssdev->manager, &timings); + return rfbi_transfer_area(dssdev, callback, data); +} +EXPORT_SYMBOL(omap_rfbi_update); - return 0; +void omapdss_rfbi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h) +{ + rfbi.timings.x_res = w; + rfbi.timings.y_res = h; } -EXPORT_SYMBOL(omap_rfbi_prepare_update); +EXPORT_SYMBOL(omapdss_rfbi_set_size); -int omap_rfbi_update(struct omap_dss_device *dssdev, - u16 x, u16 y, u16 w, u16 h, - void (*callback)(void *), void *data) +void omapdss_rfbi_set_pixel_size(struct omap_dss_device *dssdev, int pixel_size) { - int r; + rfbi.pixel_size = pixel_size; +} +EXPORT_SYMBOL(omapdss_rfbi_set_pixel_size); - r = rfbi_transfer_area(dssdev, w, h, callback, data); +void omapdss_rfbi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) +{ + rfbi.data_lines = data_lines; +} +EXPORT_SYMBOL(omapdss_rfbi_set_data_lines); - return r; +void omapdss_rfbi_set_interface_timings(struct omap_dss_device *dssdev, + struct rfbi_timings *timings) +{ + rfbi.intf_timings = *timings; } -EXPORT_SYMBOL(omap_rfbi_update); +EXPORT_SYMBOL(omapdss_rfbi_set_interface_timings); static void rfbi_dump_regs(struct seq_file *s) { @@ -869,6 +852,7 @@ static void rfbi_dump_regs(struct seq_file *s) static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) { + struct omap_overlay_manager *mgr = dssdev->output->manager; struct dss_lcd_mgr_config mgr_config; mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI; @@ -877,18 +861,40 @@ static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) /* Do we need fifohandcheck for RFBI? */ mgr_config.fifohandcheck = false; - mgr_config.video_port_width = dssdev->ctrl.pixel_size; + mgr_config.video_port_width = rfbi.pixel_size; mgr_config.lcden_sig_polarity = 0; - dss_mgr_set_lcd_config(dssdev->manager, &mgr_config); + dss_mgr_set_lcd_config(mgr, &mgr_config); + + /* + * Set rfbi.timings with default values, the x_res and y_res fields + * are expected to be already configured by the panel driver via + * omapdss_rfbi_set_size() + */ + rfbi.timings.hsw = 1; + rfbi.timings.hfp = 1; + rfbi.timings.hbp = 1; + rfbi.timings.vsw = 1; + rfbi.timings.vfp = 0; + rfbi.timings.vbp = 0; + + rfbi.timings.interlace = false; + rfbi.timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH; + rfbi.timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; + rfbi.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; + rfbi.timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; + rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; + + dss_mgr_set_timings(mgr, &rfbi.timings); } int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) { + struct omap_dss_output *out = dssdev->output; int r; - if (dssdev->manager == NULL) { - DSSERR("failed to enable display: no manager\n"); + if (out == NULL || out->manager == NULL) { + DSSERR("failed to enable display: no output/manager\n"); return -ENODEV; } @@ -911,13 +917,10 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) rfbi_config_lcd_manager(dssdev); - rfbi_configure(dssdev->phy.rfbi.channel, - dssdev->ctrl.pixel_size, - dssdev->phy.rfbi.data_lines); - - rfbi_set_timings(dssdev->phy.rfbi.channel, - &dssdev->ctrl.rfbi_timings); + rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size, + rfbi.data_lines); + rfbi_set_timings(dssdev->phy.rfbi.channel, &rfbi.intf_timings); return 0; err1: @@ -941,14 +944,17 @@ EXPORT_SYMBOL(omapdss_rfbi_display_disable); static int __init rfbi_init_display(struct omap_dss_device *dssdev) { rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev; - dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; return 0; } -static void __init rfbi_probe_pdata(struct platform_device *pdev) +static struct omap_dss_device * __init rfbi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - int i, r; + const char *def_disp_name = dss_get_default_display_name(); + struct omap_dss_device *def_dssdev; + int i; + + def_dssdev = NULL; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -956,17 +962,67 @@ static void __init rfbi_probe_pdata(struct platform_device *pdev) if (dssdev->type != OMAP_DISPLAY_TYPE_DBI) continue; - r = rfbi_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - continue; + if (def_dssdev == NULL) + def_dssdev = dssdev; + + if (def_disp_name != NULL && + strcmp(dssdev->name, def_disp_name) == 0) { + def_dssdev = dssdev; + break; } + } + + return def_dssdev; +} + +static void __init rfbi_probe_pdata(struct platform_device *rfbidev) +{ + struct omap_dss_device *plat_dssdev; + struct omap_dss_device *dssdev; + int r; + + plat_dssdev = rfbi_find_dssdev(rfbidev); + + if (!plat_dssdev) + return; + + dssdev = dss_alloc_and_init_device(&rfbidev->dev); + if (!dssdev) + return; + + dss_copy_device_pdata(dssdev, plat_dssdev); - r = omap_dss_register_device(dssdev, &pdev->dev, i); - if (r) - DSSERR("device %s register failed: %d\n", - dssdev->name, r); + r = rfbi_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; } + + r = dss_add_device(dssdev); + if (r) { + DSSERR("device %s register failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; + } +} + +static void __init rfbi_init_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &rfbi.output; + + out->pdev = pdev; + out->id = OMAP_DSS_OUTPUT_DBI; + out->type = OMAP_DISPLAY_TYPE_DBI; + + dss_register_output(out); +} + +static void __exit rfbi_uninit_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &rfbi.output; + + dss_unregister_output(out); } /* RFBI HW IP initialisation */ @@ -1020,6 +1076,8 @@ static int __init omap_rfbihw_probe(struct platform_device *pdev) dss_debugfs_create_file("rfbi", rfbi_dump_regs); + rfbi_init_output(pdev); + rfbi_probe_pdata(pdev); return 0; @@ -1031,8 +1089,12 @@ err_runtime_get: static int __exit omap_rfbihw_remove(struct platform_device *pdev) { - omap_dss_unregister_child_devices(&pdev->dev); + dss_unregister_child_devices(&pdev->dev); + + rfbi_uninit_output(pdev); + pm_runtime_disable(&pdev->dev); + return 0; } diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index f43bfe17b3b6..7760851f6e5d 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -25,6 +25,7 @@ #include <linux/regulator/consumer.h> #include <linux/export.h> #include <linux/platform_device.h> +#include <linux/string.h> #include <video/omapdss.h> #include "dss.h" @@ -34,10 +35,16 @@ static struct { struct regulator *vdds_sdi_reg; struct dss_lcd_mgr_config mgr_config; + struct omap_video_timings timings; + int datapairs; + + struct omap_dss_output output; } sdi; static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) { + struct omap_overlay_manager *mgr = dssdev->output->manager; + sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; sdi.mgr_config.stallmode = false; @@ -46,19 +53,20 @@ static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) sdi.mgr_config.video_port_width = 24; sdi.mgr_config.lcden_sig_polarity = 1; - dss_mgr_set_lcd_config(dssdev->manager, &sdi.mgr_config); + dss_mgr_set_lcd_config(mgr, &sdi.mgr_config); } int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) { - struct omap_video_timings *t = &dssdev->panel.timings; + struct omap_dss_output *out = dssdev->output; + struct omap_video_timings *t = &sdi.timings; struct dss_clock_info dss_cinfo; struct dispc_clock_info dispc_cinfo; unsigned long pck; int r; - if (dssdev->manager == NULL) { - DSSERR("failed to enable display: no manager\n"); + if (out == NULL || out->manager == NULL) { + DSSERR("failed to enable display: no output/manager\n"); return -ENODEV; } @@ -77,8 +85,8 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) goto err_get_dispc; /* 15.5.9.1.2 */ - dssdev->panel.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; - dssdev->panel.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; + t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; + t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo); if (r) @@ -97,7 +105,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) } - dss_mgr_set_timings(dssdev->manager, t); + dss_mgr_set_timings(out->manager, t); r = dss_set_clock_div(&dss_cinfo); if (r) @@ -116,16 +124,15 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) * need to care about the shadow register mechanism for pck-free. The * exact reason for this is unknown. */ - dispc_mgr_set_clock_div(dssdev->manager->id, - &sdi.mgr_config.clock_info); + dispc_mgr_set_clock_div(out->manager->id, &sdi.mgr_config.clock_info); - dss_sdi_init(dssdev->phy.sdi.datapairs); + dss_sdi_init(sdi.datapairs); r = dss_sdi_enable(); if (r) goto err_sdi_enable; mdelay(2); - r = dss_mgr_enable(dssdev->manager); + r = dss_mgr_enable(out->manager); if (r) goto err_mgr_enable; @@ -148,7 +155,9 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable); void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) { - dss_mgr_disable(dssdev->manager); + struct omap_overlay_manager *mgr = dssdev->output->manager; + + dss_mgr_disable(mgr); dss_sdi_disable(); @@ -160,6 +169,19 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) } EXPORT_SYMBOL(omapdss_sdi_display_disable); +void omapdss_sdi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + sdi.timings = *timings; +} +EXPORT_SYMBOL(omapdss_sdi_set_timings); + +void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs) +{ + sdi.datapairs = datapairs; +} +EXPORT_SYMBOL(omapdss_sdi_set_datapairs); + static int __init sdi_init_display(struct omap_dss_device *dssdev) { DSSDBG("SDI init\n"); @@ -180,10 +202,14 @@ static int __init sdi_init_display(struct omap_dss_device *dssdev) return 0; } -static void __init sdi_probe_pdata(struct platform_device *pdev) +static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - int i, r; + const char *def_disp_name = dss_get_default_display_name(); + struct omap_dss_device *def_dssdev; + int i; + + def_dssdev = NULL; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -191,21 +217,73 @@ static void __init sdi_probe_pdata(struct platform_device *pdev) if (dssdev->type != OMAP_DISPLAY_TYPE_SDI) continue; - r = sdi_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - continue; + if (def_dssdev == NULL) + def_dssdev = dssdev; + + if (def_disp_name != NULL && + strcmp(dssdev->name, def_disp_name) == 0) { + def_dssdev = dssdev; + break; } + } + + return def_dssdev; +} + +static void __init sdi_probe_pdata(struct platform_device *sdidev) +{ + struct omap_dss_device *plat_dssdev; + struct omap_dss_device *dssdev; + int r; + + plat_dssdev = sdi_find_dssdev(sdidev); - r = omap_dss_register_device(dssdev, &pdev->dev, i); - if (r) - DSSERR("device %s register failed: %d\n", - dssdev->name, r); + if (!plat_dssdev) + return; + + dssdev = dss_alloc_and_init_device(&sdidev->dev); + if (!dssdev) + return; + + dss_copy_device_pdata(dssdev, plat_dssdev); + + r = sdi_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; } + + r = dss_add_device(dssdev); + if (r) { + DSSERR("device %s register failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; + } +} + +static void __init sdi_init_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &sdi.output; + + out->pdev = pdev; + out->id = OMAP_DSS_OUTPUT_SDI; + out->type = OMAP_DISPLAY_TYPE_SDI; + + dss_register_output(out); +} + +static void __exit sdi_uninit_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &sdi.output; + + dss_unregister_output(out); } static int __init omap_sdi_probe(struct platform_device *pdev) { + sdi_init_output(pdev); + sdi_probe_pdata(pdev); return 0; @@ -213,7 +291,9 @@ static int __init omap_sdi_probe(struct platform_device *pdev) static int __exit omap_sdi_remove(struct platform_device *pdev) { - omap_dss_unregister_child_devices(&pdev->dev); + dss_unregister_child_devices(&pdev->dev); + + sdi_uninit_output(pdev); return 0; } diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 3a220877461a..56efa3bb465d 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -36,7 +36,6 @@ #include <linux/pm_runtime.h> #include <video/omapdss.h> -#include <plat/cpu.h> #include "dss.h" #include "dss_features.h" @@ -300,6 +299,12 @@ static struct { struct regulator *vdda_dac_reg; struct clk *tv_dac_clk; + + struct omap_video_timings timings; + enum omap_dss_venc_type type; + bool invert_polarity; + + struct omap_dss_output output; } venc; static inline void venc_write_reg(int idx, u32 val) @@ -424,65 +429,67 @@ static const struct venc_config *venc_timings_to_config( static int venc_power_on(struct omap_dss_device *dssdev) { + struct omap_overlay_manager *mgr = dssdev->output->manager; u32 l; int r; + r = venc_runtime_get(); + if (r) + goto err0; + venc_reset(); - venc_write_config(venc_timings_to_config(&dssdev->panel.timings)); + venc_write_config(venc_timings_to_config(&venc.timings)); - dss_set_venc_output(dssdev->phy.venc.type); + dss_set_venc_output(venc.type); dss_set_dac_pwrdn_bgz(1); l = 0; - if (dssdev->phy.venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE) + if (venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE) l |= 1 << 1; else /* S-Video */ l |= (1 << 0) | (1 << 2); - if (dssdev->phy.venc.invert_polarity == false) + if (venc.invert_polarity == false) l |= 1 << 3; venc_write_reg(VENC_OUTPUT_CONTROL, l); - dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); + dss_mgr_set_timings(mgr, &venc.timings); r = regulator_enable(venc.vdda_dac_reg); if (r) - goto err; - - if (dssdev->platform_enable) - dssdev->platform_enable(dssdev); + goto err1; - r = dss_mgr_enable(dssdev->manager); + r = dss_mgr_enable(mgr); if (r) - goto err; + goto err2; return 0; -err: +err2: + regulator_disable(venc.vdda_dac_reg); +err1: venc_write_reg(VENC_OUTPUT_CONTROL, 0); dss_set_dac_pwrdn_bgz(0); - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - - regulator_disable(venc.vdda_dac_reg); - + venc_runtime_put(); +err0: return r; } static void venc_power_off(struct omap_dss_device *dssdev) { + struct omap_overlay_manager *mgr = dssdev->output->manager; + venc_write_reg(VENC_OUTPUT_CONTROL, 0); dss_set_dac_pwrdn_bgz(0); - dss_mgr_disable(dssdev->manager); - - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); + dss_mgr_disable(mgr); regulator_disable(venc.vdda_dac_reg); + + venc_runtime_put(); } unsigned long venc_get_pixel_clock(void) @@ -491,171 +498,83 @@ unsigned long venc_get_pixel_clock(void) return 13500000; } -static ssize_t display_output_type_show(struct device *dev, - struct device_attribute *attr, char *buf) +int omapdss_venc_display_enable(struct omap_dss_device *dssdev) { - struct omap_dss_device *dssdev = to_dss_device(dev); - const char *ret; - - switch (dssdev->phy.venc.type) { - case OMAP_DSS_VENC_TYPE_COMPOSITE: - ret = "composite"; - break; - case OMAP_DSS_VENC_TYPE_SVIDEO: - ret = "svideo"; - break; - default: - return -EINVAL; - } - - return snprintf(buf, PAGE_SIZE, "%s\n", ret); -} + struct omap_dss_output *out = dssdev->output; + int r; -static ssize_t display_output_type_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct omap_dss_device *dssdev = to_dss_device(dev); - enum omap_dss_venc_type new_type; - - if (sysfs_streq("composite", buf)) - new_type = OMAP_DSS_VENC_TYPE_COMPOSITE; - else if (sysfs_streq("svideo", buf)) - new_type = OMAP_DSS_VENC_TYPE_SVIDEO; - else - return -EINVAL; + DSSDBG("venc_display_enable\n"); mutex_lock(&venc.venc_lock); - if (dssdev->phy.venc.type != new_type) { - dssdev->phy.venc.type = new_type; - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - venc_power_off(dssdev); - venc_power_on(dssdev); - } + if (out == NULL || out->manager == NULL) { + DSSERR("Failed to enable display: no output/manager\n"); + r = -ENODEV; + goto err0; } - mutex_unlock(&venc.venc_lock); - - return size; -} - -static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR, - display_output_type_show, display_output_type_store); - -/* driver */ -static int venc_panel_probe(struct omap_dss_device *dssdev) -{ - dssdev->panel.timings = omap_dss_pal_timings; - - return device_create_file(&dssdev->dev, &dev_attr_output_type); -} - -static void venc_panel_remove(struct omap_dss_device *dssdev) -{ - device_remove_file(&dssdev->dev, &dev_attr_output_type); -} - -static int venc_panel_enable(struct omap_dss_device *dssdev) -{ - int r = 0; - - DSSDBG("venc_enable_display\n"); - - mutex_lock(&venc.venc_lock); - r = omap_dss_start_device(dssdev); if (r) { DSSERR("failed to start device\n"); goto err0; } - if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { - r = -EINVAL; - goto err1; - } + if (dssdev->platform_enable) + dssdev->platform_enable(dssdev); - r = venc_runtime_get(); - if (r) - goto err1; r = venc_power_on(dssdev); if (r) - goto err2; + goto err1; venc.wss_data = 0; - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; - mutex_unlock(&venc.venc_lock); + return 0; -err2: - venc_runtime_put(); err1: + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); omap_dss_stop_device(dssdev); err0: mutex_unlock(&venc.venc_lock); - return r; } -static void venc_panel_disable(struct omap_dss_device *dssdev) +void omapdss_venc_display_disable(struct omap_dss_device *dssdev) { - DSSDBG("venc_disable_display\n"); + DSSDBG("venc_display_disable\n"); mutex_lock(&venc.venc_lock); - if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED) - goto end; - - if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) { - /* suspended is the same as disabled with venc */ - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; - goto end; - } - venc_power_off(dssdev); - venc_runtime_put(); - - dssdev->state = OMAP_DSS_DISPLAY_DISABLED; - omap_dss_stop_device(dssdev); -end: - mutex_unlock(&venc.venc_lock); -} -static int venc_panel_suspend(struct omap_dss_device *dssdev) -{ - venc_panel_disable(dssdev); - return 0; -} + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); -static int venc_panel_resume(struct omap_dss_device *dssdev) -{ - return venc_panel_enable(dssdev); + mutex_unlock(&venc.venc_lock); } -static void venc_set_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings) +void omapdss_venc_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) { DSSDBG("venc_set_timings\n"); + mutex_lock(&venc.venc_lock); + /* Reset WSS data when the TV standard changes. */ - if (memcmp(&dssdev->panel.timings, timings, sizeof(*timings))) + if (memcmp(&venc.timings, timings, sizeof(*timings))) venc.wss_data = 0; - dssdev->panel.timings = *timings; - if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { - /* turn the venc off and on to get new timings to use */ - venc_panel_disable(dssdev); - venc_panel_enable(dssdev); - } else { - dss_mgr_set_timings(dssdev->manager, timings); - } + venc.timings = *timings; + + mutex_unlock(&venc.venc_lock); } -static int venc_check_timings(struct omap_dss_device *dssdev, - struct omap_video_timings *timings) +int omapdss_venc_check_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) { DSSDBG("venc_check_timings\n"); @@ -668,13 +587,13 @@ static int venc_check_timings(struct omap_dss_device *dssdev, return -EINVAL; } -static u32 venc_get_wss(struct omap_dss_device *dssdev) +u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev) { /* Invert due to VENC_L21_WC_CTL:INV=1 */ return (venc.wss_data >> 8) ^ 0xfffff; } -static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss) +int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss) { const struct venc_config *config; int r; @@ -683,7 +602,7 @@ static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss) mutex_lock(&venc.venc_lock); - config = venc_timings_to_config(&dssdev->panel.timings); + config = venc_timings_to_config(&venc.timings); /* Invert due to VENC_L21_WC_CTL:INV=1 */ venc.wss_data = (wss ^ 0xfffff) << 8; @@ -703,30 +622,25 @@ err: return r; } -static struct omap_dss_driver venc_driver = { - .probe = venc_panel_probe, - .remove = venc_panel_remove, +void omapdss_venc_set_type(struct omap_dss_device *dssdev, + enum omap_dss_venc_type type) +{ + mutex_lock(&venc.venc_lock); - .enable = venc_panel_enable, - .disable = venc_panel_disable, - .suspend = venc_panel_suspend, - .resume = venc_panel_resume, + venc.type = type; - .get_resolution = omapdss_default_get_resolution, - .get_recommended_bpp = omapdss_default_get_recommended_bpp, + mutex_unlock(&venc.venc_lock); +} - .set_timings = venc_set_timings, - .check_timings = venc_check_timings, +void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev, + bool invert_polarity) +{ + mutex_lock(&venc.venc_lock); - .get_wss = venc_get_wss, - .set_wss = venc_set_wss, + venc.invert_polarity = invert_polarity; - .driver = { - .name = "venc", - .owner = THIS_MODULE, - }, -}; -/* driver end */ + mutex_unlock(&venc.venc_lock); +} static int __init venc_init_display(struct omap_dss_device *dssdev) { @@ -752,11 +666,6 @@ static void venc_dump_regs(struct seq_file *s) { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r)) - if (cpu_is_omap44xx()) { - seq_printf(s, "VENC currently disabled on OMAP44xx\n"); - return; - } - if (venc_runtime_get()) return; @@ -832,10 +741,14 @@ static void venc_put_clocks(void) clk_put(venc.tv_dac_clk); } -static void __init venc_probe_pdata(struct platform_device *pdev) +static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - int r, i; + const char *def_disp_name = dss_get_default_display_name(); + struct omap_dss_device *def_dssdev; + int i; + + def_dssdev = NULL; for (i = 0; i < pdata->num_devices; ++i) { struct omap_dss_device *dssdev = pdata->devices[i]; @@ -843,17 +756,69 @@ static void __init venc_probe_pdata(struct platform_device *pdev) if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) continue; - r = venc_init_display(dssdev); - if (r) { - DSSERR("device %s init failed: %d\n", dssdev->name, r); - continue; + if (def_dssdev == NULL) + def_dssdev = dssdev; + + if (def_disp_name != NULL && + strcmp(dssdev->name, def_disp_name) == 0) { + def_dssdev = dssdev; + break; } + } + + return def_dssdev; +} + +static void __init venc_probe_pdata(struct platform_device *vencdev) +{ + struct omap_dss_device *plat_dssdev; + struct omap_dss_device *dssdev; + int r; + + plat_dssdev = venc_find_dssdev(vencdev); - r = omap_dss_register_device(dssdev, &pdev->dev, i); - if (r) - DSSERR("device %s register failed: %d\n", - dssdev->name, r); + if (!plat_dssdev) + return; + + dssdev = dss_alloc_and_init_device(&vencdev->dev); + if (!dssdev) + return; + + dss_copy_device_pdata(dssdev, plat_dssdev); + + dssdev->channel = OMAP_DSS_CHANNEL_DIGIT; + + r = venc_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; } + + r = dss_add_device(dssdev); + if (r) { + DSSERR("device %s register failed: %d\n", dssdev->name, r); + dss_put_device(dssdev); + return; + } +} + +static void __init venc_init_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &venc.output; + + out->pdev = pdev; + out->id = OMAP_DSS_OUTPUT_VENC; + out->type = OMAP_DISPLAY_TYPE_VENC; + + dss_register_output(out); +} + +static void __exit venc_uninit_output(struct platform_device *pdev) +{ + struct omap_dss_output *out = &venc.output; + + dss_unregister_output(out); } /* VENC HW IP initialisation */ @@ -897,17 +862,19 @@ static int __init omap_venchw_probe(struct platform_device *pdev) venc_runtime_put(); - r = omap_dss_register_driver(&venc_driver); + r = venc_panel_init(); if (r) - goto err_reg_panel_driver; + goto err_panel_init; dss_debugfs_create_file("venc", venc_dump_regs); + venc_init_output(pdev); + venc_probe_pdata(pdev); return 0; -err_reg_panel_driver: +err_panel_init: err_runtime_get: pm_runtime_disable(&pdev->dev); venc_put_clocks(); @@ -916,14 +883,16 @@ err_runtime_get: static int __exit omap_venchw_remove(struct platform_device *pdev) { - omap_dss_unregister_child_devices(&pdev->dev); + dss_unregister_child_devices(&pdev->dev); if (venc.vdda_dac_reg != NULL) { regulator_put(venc.vdda_dac_reg); venc.vdda_dac_reg = NULL; } - omap_dss_unregister_driver(&venc_driver); + venc_panel_exit(); + + venc_uninit_output(pdev); pm_runtime_disable(&pdev->dev); venc_put_clocks(); @@ -971,16 +940,10 @@ static struct platform_driver omap_venchw_driver = { int __init venc_init_platform_driver(void) { - if (cpu_is_omap44xx()) - return 0; - return platform_driver_probe(&omap_venchw_driver, omap_venchw_probe); } void __exit venc_uninit_platform_driver(void) { - if (cpu_is_omap44xx()) - return; - platform_driver_unregister(&omap_venchw_driver); } diff --git a/drivers/video/omap2/dss/venc_panel.c b/drivers/video/omap2/dss/venc_panel.c new file mode 100644 index 000000000000..d55b8784ecfd --- /dev/null +++ b/drivers/video/omap2/dss/venc_panel.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2009 Nokia Corporation + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * + * VENC panel driver + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/mutex.h> +#include <linux/module.h> + +#include <video/omapdss.h> + +#include "dss.h" + +static struct { + struct mutex lock; +} venc_panel; + +static ssize_t display_output_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + const char *ret; + + switch (dssdev->phy.venc.type) { + case OMAP_DSS_VENC_TYPE_COMPOSITE: + ret = "composite"; + break; + case OMAP_DSS_VENC_TYPE_SVIDEO: + ret = "svideo"; + break; + default: + return -EINVAL; + } + + return snprintf(buf, PAGE_SIZE, "%s\n", ret); +} + +static ssize_t display_output_type_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + enum omap_dss_venc_type new_type; + + if (sysfs_streq("composite", buf)) + new_type = OMAP_DSS_VENC_TYPE_COMPOSITE; + else if (sysfs_streq("svideo", buf)) + new_type = OMAP_DSS_VENC_TYPE_SVIDEO; + else + return -EINVAL; + + mutex_lock(&venc_panel.lock); + + if (dssdev->phy.venc.type != new_type) { + dssdev->phy.venc.type = new_type; + omapdss_venc_set_type(dssdev, new_type); + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { + omapdss_venc_display_disable(dssdev); + omapdss_venc_display_enable(dssdev); + } + } + + mutex_unlock(&venc_panel.lock); + + return size; +} + +static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR, + display_output_type_show, display_output_type_store); + +static int venc_panel_probe(struct omap_dss_device *dssdev) +{ + /* set default timings to PAL */ + const struct omap_video_timings default_timings = { + .x_res = 720, + .y_res = 574, + .pixel_clock = 13500, + .hsw = 64, + .hfp = 12, + .hbp = 68, + .vsw = 5, + .vfp = 5, + .vbp = 41, + + .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH, + .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, + + .interlace = true, + }; + + mutex_init(&venc_panel.lock); + + dssdev->panel.timings = default_timings; + + return device_create_file(&dssdev->dev, &dev_attr_output_type); +} + +static void venc_panel_remove(struct omap_dss_device *dssdev) +{ + device_remove_file(&dssdev->dev, &dev_attr_output_type); +} + +static int venc_panel_enable(struct omap_dss_device *dssdev) +{ + int r; + + dev_dbg(&dssdev->dev, "venc_panel_enable\n"); + + mutex_lock(&venc_panel.lock); + + if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { + r = -EINVAL; + goto err; + } + + omapdss_venc_set_timings(dssdev, &dssdev->panel.timings); + omapdss_venc_set_type(dssdev, dssdev->phy.venc.type); + omapdss_venc_invert_vid_out_polarity(dssdev, + dssdev->phy.venc.invert_polarity); + + r = omapdss_venc_display_enable(dssdev); + if (r) + goto err; + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + mutex_unlock(&venc_panel.lock); + + return 0; +err: + mutex_unlock(&venc_panel.lock); + + return r; +} + +static void venc_panel_disable(struct omap_dss_device *dssdev) +{ + dev_dbg(&dssdev->dev, "venc_panel_disable\n"); + + mutex_lock(&venc_panel.lock); + + if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED) + goto end; + + if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) { + /* suspended is the same as disabled with venc */ + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; + goto end; + } + + omapdss_venc_display_disable(dssdev); + + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; +end: + mutex_unlock(&venc_panel.lock); +} + +static int venc_panel_suspend(struct omap_dss_device *dssdev) +{ + venc_panel_disable(dssdev); + return 0; +} + +static int venc_panel_resume(struct omap_dss_device *dssdev) +{ + return venc_panel_enable(dssdev); +} + +static void venc_panel_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + dev_dbg(&dssdev->dev, "venc_panel_set_timings\n"); + + mutex_lock(&venc_panel.lock); + + omapdss_venc_set_timings(dssdev, timings); + dssdev->panel.timings = *timings; + + mutex_unlock(&venc_panel.lock); +} + +static int venc_panel_check_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + dev_dbg(&dssdev->dev, "venc_panel_check_timings\n"); + + return omapdss_venc_check_timings(dssdev, timings); +} + +static u32 venc_panel_get_wss(struct omap_dss_device *dssdev) +{ + dev_dbg(&dssdev->dev, "venc_panel_get_wss\n"); + + return omapdss_venc_get_wss(dssdev); +} + +static int venc_panel_set_wss(struct omap_dss_device *dssdev, u32 wss) +{ + dev_dbg(&dssdev->dev, "venc_panel_set_wss\n"); + + return omapdss_venc_set_wss(dssdev, wss); +} + +static struct omap_dss_driver venc_driver = { + .probe = venc_panel_probe, + .remove = venc_panel_remove, + + .enable = venc_panel_enable, + .disable = venc_panel_disable, + .suspend = venc_panel_suspend, + .resume = venc_panel_resume, + + .get_resolution = omapdss_default_get_resolution, + .get_recommended_bpp = omapdss_default_get_recommended_bpp, + + .set_timings = venc_panel_set_timings, + .check_timings = venc_panel_check_timings, + + .get_wss = venc_panel_get_wss, + .set_wss = venc_panel_set_wss, + + .driver = { + .name = "venc", + .owner = THIS_MODULE, + }, +}; + +int venc_panel_init(void) +{ + return omap_dss_register_driver(&venc_driver); +} + +void venc_panel_exit(void) +{ + omap_dss_unregister_driver(&venc_driver); +} diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index c6cf372d22c5..606b89f12351 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -599,6 +599,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_dss_device *display = fb2display(fbi); + struct omap_overlay_manager *mgr; union { struct omapfb_update_window_old uwnd_o; @@ -786,12 +787,14 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) case OMAPFB_WAITFORVSYNC: DBG("ioctl WAITFORVSYNC\n"); - if (!display) { + if (!display && !display->output && !display->output->manager) { r = -EINVAL; break; } - r = display->manager->wait_for_vsync(display->manager); + mgr = display->output->manager; + + r = mgr->wait_for_vsync(mgr); break; case OMAPFB_WAITFORGO: diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 3c39aa8de928..16db1589bd91 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -1128,7 +1128,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off); vma->vm_pgoff = off >> PAGE_SHIFT; - vma->vm_flags |= VM_IO | VM_RESERVED; + /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); vma->vm_ops = &mmap_user_ops; vma->vm_private_data = rg; @@ -1593,6 +1593,20 @@ static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev) return 0; } +static void omapfb_clear_fb(struct fb_info *fbi) +{ + const struct fb_fillrect rect = { + .dx = 0, + .dy = 0, + .width = fbi->var.xres_virtual, + .height = fbi->var.yres_virtual, + .color = 0, + .rop = ROP_COPY, + }; + + cfb_fillrect(fbi, &rect); +} + int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) { struct omapfb_info *ofbi = FB2OFB(fbi); @@ -1662,6 +1676,8 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) goto err; } + omapfb_clear_fb(fbi); + return 0; err: omapfb_free_fbmem(fbi); @@ -1946,6 +1962,16 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) } } + for (i = 0; i < fbdev->num_fbs; i++) { + struct fb_info *fbi = fbdev->fbs[i]; + struct omapfb_info *ofbi = FB2OFB(fbi); + + if (ofbi->region->size == 0) + continue; + + omapfb_clear_fb(fbi); + } + DBG("fb_infos initialized\n"); for (i = 0; i < fbdev->num_fbs; i++) { @@ -2354,6 +2380,7 @@ static int __init omapfb_probe(struct platform_device *pdev) struct omap_overlay *ovl; struct omap_dss_device *def_display; struct omap_dss_device *dssdev; + struct omap_dss_device *ovl_device; DBG("omapfb_probe\n"); @@ -2427,8 +2454,9 @@ static int __init omapfb_probe(struct platform_device *pdev) /* gfx overlay should be the default one. find a display * connected to that, and use it as default display */ ovl = omap_dss_get_overlay(0); - if (ovl->manager && ovl->manager->device) { - def_display = ovl->manager->device; + ovl_device = ovl->get_device(ovl); + if (ovl_device) { + def_display = ovl_device; } else { dev_warn(&pdev->dev, "cannot find default display\n"); def_display = NULL; diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index 30361a09aecd..5ced9b334d35 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h @@ -148,8 +148,9 @@ static inline struct omap_dss_device *fb2display(struct fb_info *fbi) /* XXX: returns the display connected to first attached overlay */ for (i = 0; i < ofbi->num_overlays; i++) { - if (ofbi->overlays[i]->manager) - return ofbi->overlays[i]->manager->device; + struct omap_overlay *ovl = ofbi->overlays[i]; + + return ovl->get_device(ovl); } return NULL; diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c index 87e421e25afe..f2b15c4a75bc 100644 --- a/drivers/video/omap2/vram.c +++ b/drivers/video/omap2/vram.c @@ -34,7 +34,6 @@ #include <asm/setup.h> #include <plat/vram.h> -#include <plat/dma.h> #ifdef DEBUG #define DBG(format, ...) pr_debug("VRAM: " format, ## __VA_ARGS__) @@ -250,59 +249,6 @@ int omap_vram_reserve(unsigned long paddr, size_t size) } EXPORT_SYMBOL(omap_vram_reserve); -static void _omap_vram_dma_cb(int lch, u16 ch_status, void *data) -{ - struct completion *compl = data; - complete(compl); -} - -static int _omap_vram_clear(u32 paddr, unsigned pages) -{ - struct completion compl; - unsigned elem_count; - unsigned frame_count; - int r; - int lch; - - init_completion(&compl); - - r = omap_request_dma(OMAP_DMA_NO_DEVICE, "VRAM DMA", - _omap_vram_dma_cb, - &compl, &lch); - if (r) { - pr_err("VRAM: request_dma failed for memory clear\n"); - return -EBUSY; - } - - elem_count = pages * PAGE_SIZE / 4; - frame_count = 1; - - omap_set_dma_transfer_params(lch, OMAP_DMA_DATA_TYPE_S32, - elem_count, frame_count, - OMAP_DMA_SYNC_ELEMENT, - 0, 0); - - omap_set_dma_dest_params(lch, 0, OMAP_DMA_AMODE_POST_INC, - paddr, 0, 0); - - omap_set_dma_color_mode(lch, OMAP_DMA_CONSTANT_FILL, 0x000000); - - omap_start_dma(lch); - - if (wait_for_completion_timeout(&compl, msecs_to_jiffies(1000)) == 0) { - omap_stop_dma(lch); - pr_err("VRAM: dma timeout while clearing memory\n"); - r = -EIO; - goto err; - } - - r = 0; -err: - omap_free_dma(lch); - - return r; -} - static int _omap_vram_alloc(unsigned pages, unsigned long *paddr) { struct vram_region *rm; @@ -337,8 +283,6 @@ found: *paddr = start; - _omap_vram_clear(start, pages); - return 0; } diff --git a/drivers/video/pnx4008/Makefile b/drivers/video/pnx4008/Makefile deleted file mode 100644 index 636aaccf01fd..000000000000 --- a/drivers/video/pnx4008/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for the new PNX4008 framebuffer device driver -# - -obj-$(CONFIG_FB_PNX4008_DUM) += sdum.o -obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnxrgbfb.o - diff --git a/drivers/video/pnx4008/dum.h b/drivers/video/pnx4008/dum.h deleted file mode 100644 index 1234d4375d92..000000000000 --- a/drivers/video/pnx4008/dum.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * linux/drivers/video/pnx4008/dum.h - * - * Internal header for SDUM - * - * 2005 (c) Koninklijke Philips N.V. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#ifndef __PNX008_DUM_H__ -#define __PNX008_DUM_H__ - -#include <mach/platform.h> - -#define PNX4008_DUMCONF_VA_BASE IO_ADDRESS(PNX4008_DUMCONF_BASE) -#define PNX4008_DUM_MAIN_VA_BASE IO_ADDRESS(PNX4008_DUM_MAINCFG_BASE) - -/* DUM CFG ADDRESSES */ -#define DUM_CH_BASE_ADR (PNX4008_DUMCONF_VA_BASE + 0x00) -#define DUM_CH_MIN_ADR (PNX4008_DUMCONF_VA_BASE + 0x00) -#define DUM_CH_MAX_ADR (PNX4008_DUMCONF_VA_BASE + 0x04) -#define DUM_CH_CONF_ADR (PNX4008_DUMCONF_VA_BASE + 0x08) -#define DUM_CH_STAT_ADR (PNX4008_DUMCONF_VA_BASE + 0x0C) -#define DUM_CH_CTRL_ADR (PNX4008_DUMCONF_VA_BASE + 0x10) - -#define CH_MARG (0x100 / sizeof(u32)) -#define DUM_CH_MIN(i) (*((volatile u32 *)DUM_CH_MIN_ADR + (i) * CH_MARG)) -#define DUM_CH_MAX(i) (*((volatile u32 *)DUM_CH_MAX_ADR + (i) * CH_MARG)) -#define DUM_CH_CONF(i) (*((volatile u32 *)DUM_CH_CONF_ADR + (i) * CH_MARG)) -#define DUM_CH_STAT(i) (*((volatile u32 *)DUM_CH_STAT_ADR + (i) * CH_MARG)) -#define DUM_CH_CTRL(i) (*((volatile u32 *)DUM_CH_CTRL_ADR + (i) * CH_MARG)) - -#define DUM_CONF_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x00) -#define DUM_CTRL_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x04) -#define DUM_STAT_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x08) -#define DUM_DECODE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x0C) -#define DUM_COM_BASE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x10) -#define DUM_SYNC_C_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x14) -#define DUM_CLK_DIV_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x18) -#define DUM_DIRTY_LOW_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x20) -#define DUM_DIRTY_HIGH_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x24) -#define DUM_FORMAT_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x28) -#define DUM_WTCFG1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x30) -#define DUM_RTCFG1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x34) -#define DUM_WTCFG2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x38) -#define DUM_RTCFG2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x3C) -#define DUM_TCFG_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x40) -#define DUM_OUTP_FORMAT1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x44) -#define DUM_OUTP_FORMAT2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x48) -#define DUM_SYNC_MODE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x4C) -#define DUM_SYNC_OUT_C_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x50) - -#define DUM_CONF (*(volatile u32 *)(DUM_CONF_ADR)) -#define DUM_CTRL (*(volatile u32 *)(DUM_CTRL_ADR)) -#define DUM_STAT (*(volatile u32 *)(DUM_STAT_ADR)) -#define DUM_DECODE (*(volatile u32 *)(DUM_DECODE_ADR)) -#define DUM_COM_BASE (*(volatile u32 *)(DUM_COM_BASE_ADR)) -#define DUM_SYNC_C (*(volatile u32 *)(DUM_SYNC_C_ADR)) -#define DUM_CLK_DIV (*(volatile u32 *)(DUM_CLK_DIV_ADR)) -#define DUM_DIRTY_LOW (*(volatile u32 *)(DUM_DIRTY_LOW_ADR)) -#define DUM_DIRTY_HIGH (*(volatile u32 *)(DUM_DIRTY_HIGH_ADR)) -#define DUM_FORMAT (*(volatile u32 *)(DUM_FORMAT_ADR)) -#define DUM_WTCFG1 (*(volatile u32 *)(DUM_WTCFG1_ADR)) -#define DUM_RTCFG1 (*(volatile u32 *)(DUM_RTCFG1_ADR)) -#define DUM_WTCFG2 (*(volatile u32 *)(DUM_WTCFG2_ADR)) -#define DUM_RTCFG2 (*(volatile u32 *)(DUM_RTCFG2_ADR)) -#define DUM_TCFG (*(volatile u32 *)(DUM_TCFG_ADR)) -#define DUM_OUTP_FORMAT1 (*(volatile u32 *)(DUM_OUTP_FORMAT1_ADR)) -#define DUM_OUTP_FORMAT2 (*(volatile u32 *)(DUM_OUTP_FORMAT2_ADR)) -#define DUM_SYNC_MODE (*(volatile u32 *)(DUM_SYNC_MODE_ADR)) -#define DUM_SYNC_OUT_C (*(volatile u32 *)(DUM_SYNC_OUT_C_ADR)) - -/* DUM SLAVE ADDRESSES */ -#define DUM_SLAVE_WRITE_ADR (PNX4008_DUM_MAINCFG_BASE + 0x0000000) -#define DUM_SLAVE_READ1_I_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000000) -#define DUM_SLAVE_READ1_R_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000004) -#define DUM_SLAVE_READ2_I_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000008) -#define DUM_SLAVE_READ2_R_ADR (PNX4008_DUM_MAINCFG_BASE + 0x100000C) - -#define DUM_SLAVE_WRITE_W ((volatile u32 *)(DUM_SLAVE_WRITE_ADR)) -#define DUM_SLAVE_WRITE_HW ((volatile u16 *)(DUM_SLAVE_WRITE_ADR)) -#define DUM_SLAVE_READ1_I ((volatile u8 *)(DUM_SLAVE_READ1_I_ADR)) -#define DUM_SLAVE_READ1_R ((volatile u16 *)(DUM_SLAVE_READ1_R_ADR)) -#define DUM_SLAVE_READ2_I ((volatile u8 *)(DUM_SLAVE_READ2_I_ADR)) -#define DUM_SLAVE_READ2_R ((volatile u16 *)(DUM_SLAVE_READ2_R_ADR)) - -/* Sony display register addresses */ -#define DISP_0_REG (0x00) -#define DISP_1_REG (0x01) -#define DISP_CAL_REG (0x20) -#define DISP_ID_REG (0x2A) -#define DISP_XMIN_L_REG (0x30) -#define DISP_XMIN_H_REG (0x31) -#define DISP_YMIN_REG (0x32) -#define DISP_XMAX_L_REG (0x34) -#define DISP_XMAX_H_REG (0x35) -#define DISP_YMAX_REG (0x36) -#define DISP_SYNC_EN_REG (0x38) -#define DISP_SYNC_RISE_L_REG (0x3C) -#define DISP_SYNC_RISE_H_REG (0x3D) -#define DISP_SYNC_FALL_L_REG (0x3E) -#define DISP_SYNC_FALL_H_REG (0x3F) -#define DISP_PIXEL_REG (0x0B) -#define DISP_DUMMY1_REG (0x28) -#define DISP_DUMMY2_REG (0x29) -#define DISP_TIMING_REG (0x98) -#define DISP_DUMP_REG (0x99) - -/* Sony display constants */ -#define SONY_ID1 (0x22) -#define SONY_ID2 (0x23) - -/* Philips display register addresses */ -#define PH_DISP_ORIENT_REG (0x003) -#define PH_DISP_YPOINT_REG (0x200) -#define PH_DISP_XPOINT_REG (0x201) -#define PH_DISP_PIXEL_REG (0x202) -#define PH_DISP_YMIN_REG (0x406) -#define PH_DISP_YMAX_REG (0x407) -#define PH_DISP_XMIN_REG (0x408) -#define PH_DISP_XMAX_REG (0x409) - -/* Misc constants */ -#define NO_VALID_DISPLAY_FOUND (0) -#define DISPLAY2_IS_NOT_CONNECTED (0) - -/* register values */ -#define V_BAC_ENABLE (BIT(0)) -#define V_BAC_DISABLE_IDLE (BIT(1)) -#define V_BAC_DISABLE_TRIG (BIT(2)) -#define V_DUM_RESET (BIT(3)) -#define V_MUX_RESET (BIT(4)) -#define BAC_ENABLED (BIT(0)) -#define BAC_DISABLED 0 - -/* Sony LCD commands */ -#define V_LCD_STANDBY_OFF ((BIT(25)) | (0 << 16) | DISP_0_REG) -#define V_LCD_USE_9BIT_BUS ((BIT(25)) | (2 << 16) | DISP_1_REG) -#define V_LCD_SYNC_RISE_L ((BIT(25)) | (0 << 16) | DISP_SYNC_RISE_L_REG) -#define V_LCD_SYNC_RISE_H ((BIT(25)) | (0 << 16) | DISP_SYNC_RISE_H_REG) -#define V_LCD_SYNC_FALL_L ((BIT(25)) | (160 << 16) | DISP_SYNC_FALL_L_REG) -#define V_LCD_SYNC_FALL_H ((BIT(25)) | (0 << 16) | DISP_SYNC_FALL_H_REG) -#define V_LCD_SYNC_ENABLE ((BIT(25)) | (128 << 16) | DISP_SYNC_EN_REG) -#define V_LCD_DISPLAY_ON ((BIT(25)) | (64 << 16) | DISP_0_REG) - -enum { - PAD_NONE, - PAD_512, - PAD_1024 -}; - -enum { - RGB888, - RGB666, - RGB565, - BGR565, - ARGB1555, - ABGR1555, - ARGB4444, - ABGR4444 -}; - -struct dum_setup { - int sync_neg_edge; - int round_robin; - int mux_int; - int synced_dirty_flag_int; - int dirty_flag_int; - int error_int; - int pf_empty_int; - int sf_empty_int; - int bac_dis_int; - u32 dirty_base_adr; - u32 command_base_adr; - u32 sync_clk_div; - int sync_output; - u32 sync_restart_val; - u32 set_sync_high; - u32 set_sync_low; -}; - -struct dum_ch_setup { - int disp_no; - u32 xmin; - u32 ymin; - u32 xmax; - u32 ymax; - int xmirror; - int ymirror; - int rotate; - u32 minadr; - u32 maxadr; - u32 dirtybuffer; - int pad; - int format; - int hwdirty; - int slave_trans; -}; - -struct disp_window { - u32 xmin_l; - u32 xmin_h; - u32 ymin; - u32 xmax_l; - u32 xmax_h; - u32 ymax; -}; - -#endif /* #ifndef __PNX008_DUM_H__ */ diff --git a/drivers/video/pnx4008/fbcommon.h b/drivers/video/pnx4008/fbcommon.h deleted file mode 100644 index 4ebc87dafafb..000000000000 --- a/drivers/video/pnx4008/fbcommon.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2005 Philips Semiconductors - * - * 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 Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA, or http://www.gnu.org/licenses/gpl.html -*/ - -#define QCIF_W (176) -#define QCIF_H (144) - -#define CIF_W (352) -#define CIF_H (288) - -#define LCD_X_RES 208 -#define LCD_Y_RES 320 -#define LCD_X_PAD 256 -#define LCD_BBP 4 /* Bytes Per Pixel */ - -#define DISP_MAX_X_SIZE (320) -#define DISP_MAX_Y_SIZE (208) - -#define RETURNVAL_BASE (0x400) - -enum fb_ioctl_returntype { - ENORESOURCESLEFT = RETURNVAL_BASE, - ERESOURCESNOTFREED, - EPROCNOTOWNER, - EFBNOTOWNER, - ECOPYFAILED, - EIOREMAPFAILED, -}; diff --git a/drivers/video/pnx4008/pnxrgbfb.c b/drivers/video/pnx4008/pnxrgbfb.c deleted file mode 100644 index 6d30428e9cf9..000000000000 --- a/drivers/video/pnx4008/pnxrgbfb.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * drivers/video/pnx4008/pnxrgbfb.c - * - * PNX4008's framebuffer support - * - * Author: Grigory Tolstolytkin <gtolstolytkin@ru.mvista.com> - * Based on Philips Semiconductors's code - * - * Copyrght (c) 2005 MontaVista Software, Inc. - * Copyright (c) 2005 Philips Semiconductors - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/vmalloc.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/fb.h> -#include <linux/init.h> -#include <linux/platform_device.h> - -#include "sdum.h" -#include "fbcommon.h" - -static u32 colreg[16]; - -static struct fb_var_screeninfo rgbfb_var __initdata = { - .xres = LCD_X_RES, - .yres = LCD_Y_RES, - .xres_virtual = LCD_X_RES, - .yres_virtual = LCD_Y_RES, - .bits_per_pixel = 32, - .red.offset = 16, - .red.length = 8, - .green.offset = 8, - .green.length = 8, - .blue.offset = 0, - .blue.length = 8, - .left_margin = 0, - .right_margin = 0, - .upper_margin = 0, - .lower_margin = 0, - .vmode = FB_VMODE_NONINTERLACED, -}; -static struct fb_fix_screeninfo rgbfb_fix __initdata = { - .id = "RGBFB", - .line_length = LCD_X_RES * LCD_BBP, - .type = FB_TYPE_PACKED_PIXELS, - .visual = FB_VISUAL_TRUECOLOR, - .xpanstep = 0, - .ypanstep = 0, - .ywrapstep = 0, - .accel = FB_ACCEL_NONE, -}; - -static int channel_owned; - -static int no_cursor(struct fb_info *info, struct fb_cursor *cursor) -{ - return 0; -} - -static int rgbfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) -{ - if (regno > 15) - return 1; - - colreg[regno] = ((red & 0xff00) << 8) | (green & 0xff00) | - ((blue & 0xff00) >> 8); - return 0; -} - -static int rgbfb_mmap(struct fb_info *info, struct vm_area_struct *vma) -{ - return pnx4008_sdum_mmap(info, vma, NULL); -} - -static struct fb_ops rgbfb_ops = { - .fb_mmap = rgbfb_mmap, - .fb_setcolreg = rgbfb_setcolreg, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, -}; - -static int rgbfb_remove(struct platform_device *pdev) -{ - struct fb_info *info = platform_get_drvdata(pdev); - - if (info) { - unregister_framebuffer(info); - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - platform_set_drvdata(pdev, NULL); - } - - pnx4008_free_dum_channel(channel_owned, pdev->id); - pnx4008_set_dum_exit_notification(pdev->id); - - return 0; -} - -static int __devinit rgbfb_probe(struct platform_device *pdev) -{ - struct fb_info *info; - struct dumchannel_uf chan_uf; - int ret; - char *option; - - info = framebuffer_alloc(sizeof(u32) * 16, &pdev->dev); - if (!info) { - ret = -ENOMEM; - goto err; - } - - pnx4008_get_fb_addresses(FB_TYPE_RGB, (void **)&info->screen_base, - (dma_addr_t *) &rgbfb_fix.smem_start, - &rgbfb_fix.smem_len); - - if ((ret = pnx4008_alloc_dum_channel(pdev->id)) < 0) - goto err0; - else { - channel_owned = ret; - chan_uf.channelnr = channel_owned; - chan_uf.dirty = (u32 *) NULL; - chan_uf.source = (u32 *) rgbfb_fix.smem_start; - chan_uf.x_offset = 0; - chan_uf.y_offset = 0; - chan_uf.width = LCD_X_RES; - chan_uf.height = LCD_Y_RES; - - if ((ret = pnx4008_put_dum_channel_uf(chan_uf, pdev->id))< 0) - goto err1; - - if ((ret = - pnx4008_set_dum_channel_sync(channel_owned, CONF_SYNC_ON, - pdev->id)) < 0) - goto err1; - - if ((ret = - pnx4008_set_dum_channel_dirty_detect(channel_owned, - CONF_DIRTYDETECTION_ON, - pdev->id)) < 0) - goto err1; - } - - if (!fb_get_options("pnxrgbfb", &option) && option && - !strcmp(option, "nocursor")) - rgbfb_ops.fb_cursor = no_cursor; - - info->node = -1; - info->flags = FBINFO_FLAG_DEFAULT; - info->fbops = &rgbfb_ops; - info->fix = rgbfb_fix; - info->var = rgbfb_var; - info->screen_size = rgbfb_fix.smem_len; - info->pseudo_palette = info->par; - info->par = NULL; - - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret < 0) - goto err1; - - ret = register_framebuffer(info); - if (ret < 0) - goto err2; - platform_set_drvdata(pdev, info); - - return 0; - -err2: - fb_dealloc_cmap(&info->cmap); -err1: - pnx4008_free_dum_channel(channel_owned, pdev->id); -err0: - framebuffer_release(info); -err: - return ret; -} - -static struct platform_driver rgbfb_driver = { - .driver = { - .name = "pnx4008-rgbfb", - }, - .probe = rgbfb_probe, - .remove = rgbfb_remove, -}; - -module_platform_driver(rgbfb_driver); - -MODULE_LICENSE("GPL"); diff --git a/drivers/video/pnx4008/sdum.c b/drivers/video/pnx4008/sdum.c deleted file mode 100644 index c5c741452cac..000000000000 --- a/drivers/video/pnx4008/sdum.c +++ /dev/null @@ -1,861 +0,0 @@ -/* - * drivers/video/pnx4008/sdum.c - * - * Display Update Master support - * - * Authors: Grigory Tolstolytkin <gtolstolytkin@ru.mvista.com> - * Vitaly Wool <vitalywool@gmail.com> - * Based on Philips Semiconductors's code - * - * Copyrght (c) 2005-2006 MontaVista Software, Inc. - * Copyright (c) 2005 Philips Semiconductors - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/tty.h> -#include <linux/vmalloc.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/fb.h> -#include <linux/init.h> -#include <linux/dma-mapping.h> -#include <linux/clk.h> -#include <linux/gfp.h> -#include <asm/uaccess.h> -#include <asm/gpio.h> - -#include "sdum.h" -#include "fbcommon.h" -#include "dum.h" - -/* Framebuffers we have */ - -static struct pnx4008_fb_addr { - int fb_type; - long addr_offset; - long fb_length; -} fb_addr[] = { - [0] = { - FB_TYPE_YUV, 0, 0xB0000 - }, - [1] = { - FB_TYPE_RGB, 0xB0000, 0x50000 - }, -}; - -static struct dum_data { - u32 lcd_phys_start; - u32 lcd_virt_start; - u32 slave_phys_base; - u32 *slave_virt_base; - int fb_owning_channel[MAX_DUM_CHANNELS]; - struct dumchannel_uf chan_uf_store[MAX_DUM_CHANNELS]; -} dum_data; - -/* Different local helper functions */ - -static u32 nof_pixels_dx(struct dum_ch_setup *ch_setup) -{ - return (ch_setup->xmax - ch_setup->xmin + 1); -} - -static u32 nof_pixels_dy(struct dum_ch_setup *ch_setup) -{ - return (ch_setup->ymax - ch_setup->ymin + 1); -} - -static u32 nof_pixels_dxy(struct dum_ch_setup *ch_setup) -{ - return (nof_pixels_dx(ch_setup) * nof_pixels_dy(ch_setup)); -} - -static u32 nof_bytes(struct dum_ch_setup *ch_setup) -{ - u32 r = nof_pixels_dxy(ch_setup); - switch (ch_setup->format) { - case RGB888: - case RGB666: - r *= 4; - break; - - default: - r *= 2; - break; - } - return r; -} - -static u32 build_command(int disp_no, u32 reg, u32 val) -{ - return ((disp_no << 26) | BIT(25) | (val << 16) | (disp_no << 10) | - (reg << 0)); -} - -static u32 build_double_index(int disp_no, u32 val) -{ - return ((disp_no << 26) | (val << 16) | (disp_no << 10) | (val << 0)); -} - -static void build_disp_window(struct dum_ch_setup * ch_setup, struct disp_window * dw) -{ - dw->ymin = ch_setup->ymin; - dw->ymax = ch_setup->ymax; - dw->xmin_l = ch_setup->xmin & 0xFF; - dw->xmin_h = (ch_setup->xmin & BIT(8)) >> 8; - dw->xmax_l = ch_setup->xmax & 0xFF; - dw->xmax_h = (ch_setup->xmax & BIT(8)) >> 8; -} - -static int put_channel(struct dumchannel chan) -{ - int i = chan.channelnr; - - if (i < 0 || i > MAX_DUM_CHANNELS) - return -EINVAL; - else { - DUM_CH_MIN(i) = chan.dum_ch_min; - DUM_CH_MAX(i) = chan.dum_ch_max; - DUM_CH_CONF(i) = chan.dum_ch_conf; - DUM_CH_CTRL(i) = chan.dum_ch_ctrl; - } - - return 0; -} - -static void clear_channel(int channr) -{ - struct dumchannel chan; - - chan.channelnr = channr; - chan.dum_ch_min = 0; - chan.dum_ch_max = 0; - chan.dum_ch_conf = 0; - chan.dum_ch_ctrl = 0; - - put_channel(chan); -} - -static int put_cmd_string(struct cmdstring cmds) -{ - u16 *cmd_str_virtaddr; - u32 *cmd_ptr0_virtaddr; - u32 cmd_str_physaddr; - - int i = cmds.channelnr; - - if (i < 0 || i > MAX_DUM_CHANNELS) - return -EINVAL; - else if ((cmd_ptr0_virtaddr = - (int *)ioremap_nocache(DUM_COM_BASE, - sizeof(int) * MAX_DUM_CHANNELS)) == - NULL) - return -EIOREMAPFAILED; - else { - cmd_str_physaddr = ioread32(&cmd_ptr0_virtaddr[cmds.channelnr]); - if ((cmd_str_virtaddr = - (u16 *) ioremap_nocache(cmd_str_physaddr, - sizeof(cmds))) == NULL) { - iounmap(cmd_ptr0_virtaddr); - return -EIOREMAPFAILED; - } else { - int t; - for (t = 0; t < 8; t++) - iowrite16(*((u16 *)&cmds.prestringlen + t), - cmd_str_virtaddr + t); - - for (t = 0; t < cmds.prestringlen / 2; t++) - iowrite16(*((u16 *)&cmds.precmd + t), - cmd_str_virtaddr + t + 8); - - for (t = 0; t < cmds.poststringlen / 2; t++) - iowrite16(*((u16 *)&cmds.postcmd + t), - cmd_str_virtaddr + t + 8 + - cmds.prestringlen / 2); - - iounmap(cmd_ptr0_virtaddr); - iounmap(cmd_str_virtaddr); - } - } - - return 0; -} - -static u32 dum_ch_setup(int ch_no, struct dum_ch_setup * ch_setup) -{ - struct cmdstring cmds_c; - struct cmdstring *cmds = &cmds_c; - struct disp_window dw; - int standard; - u32 orientation = 0; - struct dumchannel chan = { 0 }; - int ret; - - if ((ch_setup->xmirror) || (ch_setup->ymirror) || (ch_setup->rotate)) { - standard = 0; - - orientation = BIT(1); /* always set 9-bit-bus */ - if (ch_setup->xmirror) - orientation |= BIT(4); - if (ch_setup->ymirror) - orientation |= BIT(3); - if (ch_setup->rotate) - orientation |= BIT(0); - } else - standard = 1; - - cmds->channelnr = ch_no; - - /* build command string header */ - if (standard) { - cmds->prestringlen = 32; - cmds->poststringlen = 0; - } else { - cmds->prestringlen = 48; - cmds->poststringlen = 16; - } - - cmds->format = - (u16) ((ch_setup->disp_no << 4) | (BIT(3)) | (ch_setup->format)); - cmds->reserved = 0x0; - cmds->startaddr_low = (ch_setup->minadr & 0xFFFF); - cmds->startaddr_high = (ch_setup->minadr >> 16); - - if ((ch_setup->minadr == 0) && (ch_setup->maxadr == 0) - && (ch_setup->xmin == 0) - && (ch_setup->ymin == 0) && (ch_setup->xmax == 0) - && (ch_setup->ymax == 0)) { - cmds->pixdatlen_low = 0; - cmds->pixdatlen_high = 0; - } else { - u32 nbytes = nof_bytes(ch_setup); - cmds->pixdatlen_low = (nbytes & 0xFFFF); - cmds->pixdatlen_high = (nbytes >> 16); - } - - if (ch_setup->slave_trans) - cmds->pixdatlen_high |= BIT(15); - - /* build pre-string */ - build_disp_window(ch_setup, &dw); - - if (standard) { - cmds->precmd[0] = - build_command(ch_setup->disp_no, DISP_XMIN_L_REG, 0x99); - cmds->precmd[1] = - build_command(ch_setup->disp_no, DISP_XMIN_L_REG, - dw.xmin_l); - cmds->precmd[2] = - build_command(ch_setup->disp_no, DISP_XMIN_H_REG, - dw.xmin_h); - cmds->precmd[3] = - build_command(ch_setup->disp_no, DISP_YMIN_REG, dw.ymin); - cmds->precmd[4] = - build_command(ch_setup->disp_no, DISP_XMAX_L_REG, - dw.xmax_l); - cmds->precmd[5] = - build_command(ch_setup->disp_no, DISP_XMAX_H_REG, - dw.xmax_h); - cmds->precmd[6] = - build_command(ch_setup->disp_no, DISP_YMAX_REG, dw.ymax); - cmds->precmd[7] = - build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); - } else { - if (dw.xmin_l == ch_no) - cmds->precmd[0] = - build_command(ch_setup->disp_no, DISP_XMIN_L_REG, - 0x99); - else - cmds->precmd[0] = - build_command(ch_setup->disp_no, DISP_XMIN_L_REG, - ch_no); - - cmds->precmd[1] = - build_command(ch_setup->disp_no, DISP_XMIN_L_REG, - dw.xmin_l); - cmds->precmd[2] = - build_command(ch_setup->disp_no, DISP_XMIN_H_REG, - dw.xmin_h); - cmds->precmd[3] = - build_command(ch_setup->disp_no, DISP_YMIN_REG, dw.ymin); - cmds->precmd[4] = - build_command(ch_setup->disp_no, DISP_XMAX_L_REG, - dw.xmax_l); - cmds->precmd[5] = - build_command(ch_setup->disp_no, DISP_XMAX_H_REG, - dw.xmax_h); - cmds->precmd[6] = - build_command(ch_setup->disp_no, DISP_YMAX_REG, dw.ymax); - cmds->precmd[7] = - build_command(ch_setup->disp_no, DISP_1_REG, orientation); - cmds->precmd[8] = - build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); - cmds->precmd[9] = - build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); - cmds->precmd[0xA] = - build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); - cmds->precmd[0xB] = - build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); - cmds->postcmd[0] = - build_command(ch_setup->disp_no, DISP_1_REG, BIT(1)); - cmds->postcmd[1] = - build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 1); - cmds->postcmd[2] = - build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 2); - cmds->postcmd[3] = - build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 3); - } - - if ((ret = put_cmd_string(cmds_c)) != 0) { - return ret; - } - - chan.channelnr = cmds->channelnr; - chan.dum_ch_min = ch_setup->dirtybuffer + ch_setup->minadr; - chan.dum_ch_max = ch_setup->dirtybuffer + ch_setup->maxadr; - chan.dum_ch_conf = 0x002; - chan.dum_ch_ctrl = 0x04; - - put_channel(chan); - - return 0; -} - -static u32 display_open(int ch_no, int auto_update, u32 * dirty_buffer, - u32 * frame_buffer, u32 xpos, u32 ypos, u32 w, u32 h) -{ - - struct dum_ch_setup k; - int ret; - - /* keep width & height within display area */ - if ((xpos + w) > DISP_MAX_X_SIZE) - w = DISP_MAX_X_SIZE - xpos; - - if ((ypos + h) > DISP_MAX_Y_SIZE) - h = DISP_MAX_Y_SIZE - ypos; - - /* assume 1 display only */ - k.disp_no = 0; - k.xmin = xpos; - k.ymin = ypos; - k.xmax = xpos + (w - 1); - k.ymax = ypos + (h - 1); - - /* adjust min and max values if necessary */ - if (k.xmin > DISP_MAX_X_SIZE - 1) - k.xmin = DISP_MAX_X_SIZE - 1; - if (k.ymin > DISP_MAX_Y_SIZE - 1) - k.ymin = DISP_MAX_Y_SIZE - 1; - - if (k.xmax > DISP_MAX_X_SIZE - 1) - k.xmax = DISP_MAX_X_SIZE - 1; - if (k.ymax > DISP_MAX_Y_SIZE - 1) - k.ymax = DISP_MAX_Y_SIZE - 1; - - k.xmirror = 0; - k.ymirror = 0; - k.rotate = 0; - k.minadr = (u32) frame_buffer; - k.maxadr = (u32) frame_buffer + (((w - 1) << 10) | ((h << 2) - 2)); - k.pad = PAD_1024; - k.dirtybuffer = (u32) dirty_buffer; - k.format = RGB888; - k.hwdirty = 0; - k.slave_trans = 0; - - ret = dum_ch_setup(ch_no, &k); - - return ret; -} - -static void lcd_reset(void) -{ - u32 *dum_pio_base = (u32 *)IO_ADDRESS(PNX4008_PIO_BASE); - - udelay(1); - iowrite32(BIT(19), &dum_pio_base[2]); - udelay(1); - iowrite32(BIT(19), &dum_pio_base[1]); - udelay(1); -} - -static int dum_init(struct platform_device *pdev) -{ - struct clk *clk; - - /* enable DUM clock */ - clk = clk_get(&pdev->dev, "dum_ck"); - if (IS_ERR(clk)) { - printk(KERN_ERR "pnx4008_dum: Unable to access DUM clock\n"); - return PTR_ERR(clk); - } - - clk_set_rate(clk, 1); - clk_put(clk); - - DUM_CTRL = V_DUM_RESET; - - /* set priority to "round-robin". All other params to "false" */ - DUM_CONF = BIT(9); - - /* Display 1 */ - DUM_WTCFG1 = PNX4008_DUM_WT_CFG; - DUM_RTCFG1 = PNX4008_DUM_RT_CFG; - DUM_TCFG = PNX4008_DUM_T_CFG; - - return 0; -} - -static void dum_chan_init(void) -{ - int i = 0, ch = 0; - u32 *cmdptrs; - u32 *cmdstrings; - - DUM_COM_BASE = - CMDSTRING_BASEADDR + BYTES_PER_CMDSTRING * NR_OF_CMDSTRINGS; - - if ((cmdptrs = - (u32 *) ioremap_nocache(DUM_COM_BASE, - sizeof(u32) * NR_OF_CMDSTRINGS)) == NULL) - return; - - for (ch = 0; ch < NR_OF_CMDSTRINGS; ch++) - iowrite32(CMDSTRING_BASEADDR + BYTES_PER_CMDSTRING * ch, - cmdptrs + ch); - - for (ch = 0; ch < MAX_DUM_CHANNELS; ch++) - clear_channel(ch); - - /* Clear the cmdstrings */ - cmdstrings = - (u32 *)ioremap_nocache(*cmdptrs, - BYTES_PER_CMDSTRING * NR_OF_CMDSTRINGS); - - if (!cmdstrings) - goto out; - - for (i = 0; i < NR_OF_CMDSTRINGS * BYTES_PER_CMDSTRING / sizeof(u32); - i++) - iowrite32(0, cmdstrings + i); - - iounmap((u32 *)cmdstrings); - -out: - iounmap((u32 *)cmdptrs); -} - -static void lcd_init(void) -{ - lcd_reset(); - - DUM_OUTP_FORMAT1 = 0; /* RGB666 */ - - udelay(1); - iowrite32(V_LCD_STANDBY_OFF, dum_data.slave_virt_base); - udelay(1); - iowrite32(V_LCD_USE_9BIT_BUS, dum_data.slave_virt_base); - udelay(1); - iowrite32(V_LCD_SYNC_RISE_L, dum_data.slave_virt_base); - udelay(1); - iowrite32(V_LCD_SYNC_RISE_H, dum_data.slave_virt_base); - udelay(1); - iowrite32(V_LCD_SYNC_FALL_L, dum_data.slave_virt_base); - udelay(1); - iowrite32(V_LCD_SYNC_FALL_H, dum_data.slave_virt_base); - udelay(1); - iowrite32(V_LCD_SYNC_ENABLE, dum_data.slave_virt_base); - udelay(1); - iowrite32(V_LCD_DISPLAY_ON, dum_data.slave_virt_base); - udelay(1); -} - -/* Interface exported to framebuffer drivers */ - -int pnx4008_get_fb_addresses(int fb_type, void **virt_addr, - dma_addr_t *phys_addr, int *fb_length) -{ - int i; - int ret = -1; - for (i = 0; i < ARRAY_SIZE(fb_addr); i++) - if (fb_addr[i].fb_type == fb_type) { - *virt_addr = (void *)(dum_data.lcd_virt_start + - fb_addr[i].addr_offset); - *phys_addr = - dum_data.lcd_phys_start + fb_addr[i].addr_offset; - *fb_length = fb_addr[i].fb_length; - ret = 0; - break; - } - - return ret; -} - -EXPORT_SYMBOL(pnx4008_get_fb_addresses); - -int pnx4008_alloc_dum_channel(int dev_id) -{ - int i = 0; - - while ((i < MAX_DUM_CHANNELS) && (dum_data.fb_owning_channel[i] != -1)) - i++; - - if (i == MAX_DUM_CHANNELS) - return -ENORESOURCESLEFT; - else { - dum_data.fb_owning_channel[i] = dev_id; - return i; - } -} - -EXPORT_SYMBOL(pnx4008_alloc_dum_channel); - -int pnx4008_free_dum_channel(int channr, int dev_id) -{ - if (channr < 0 || channr > MAX_DUM_CHANNELS) - return -EINVAL; - else if (dum_data.fb_owning_channel[channr] != dev_id) - return -EFBNOTOWNER; - else { - clear_channel(channr); - dum_data.fb_owning_channel[channr] = -1; - } - - return 0; -} - -EXPORT_SYMBOL(pnx4008_free_dum_channel); - -int pnx4008_put_dum_channel_uf(struct dumchannel_uf chan_uf, int dev_id) -{ - int i = chan_uf.channelnr; - int ret; - - if (i < 0 || i > MAX_DUM_CHANNELS) - return -EINVAL; - else if (dum_data.fb_owning_channel[i] != dev_id) - return -EFBNOTOWNER; - else if ((ret = - display_open(chan_uf.channelnr, 0, chan_uf.dirty, - chan_uf.source, chan_uf.y_offset, - chan_uf.x_offset, chan_uf.height, - chan_uf.width)) != 0) - return ret; - else { - dum_data.chan_uf_store[i].dirty = chan_uf.dirty; - dum_data.chan_uf_store[i].source = chan_uf.source; - dum_data.chan_uf_store[i].x_offset = chan_uf.x_offset; - dum_data.chan_uf_store[i].y_offset = chan_uf.y_offset; - dum_data.chan_uf_store[i].width = chan_uf.width; - dum_data.chan_uf_store[i].height = chan_uf.height; - } - - return 0; -} - -EXPORT_SYMBOL(pnx4008_put_dum_channel_uf); - -int pnx4008_set_dum_channel_sync(int channr, int val, int dev_id) -{ - if (channr < 0 || channr > MAX_DUM_CHANNELS) - return -EINVAL; - else if (dum_data.fb_owning_channel[channr] != dev_id) - return -EFBNOTOWNER; - else { - if (val == CONF_SYNC_ON) { - DUM_CH_CONF(channr) |= CONF_SYNCENABLE; - DUM_CH_CONF(channr) |= DUM_CHANNEL_CFG_SYNC_MASK | - DUM_CHANNEL_CFG_SYNC_MASK_SET; - } else if (val == CONF_SYNC_OFF) - DUM_CH_CONF(channr) &= ~CONF_SYNCENABLE; - else - return -EINVAL; - } - - return 0; -} - -EXPORT_SYMBOL(pnx4008_set_dum_channel_sync); - -int pnx4008_set_dum_channel_dirty_detect(int channr, int val, int dev_id) -{ - if (channr < 0 || channr > MAX_DUM_CHANNELS) - return -EINVAL; - else if (dum_data.fb_owning_channel[channr] != dev_id) - return -EFBNOTOWNER; - else { - if (val == CONF_DIRTYDETECTION_ON) - DUM_CH_CONF(channr) |= CONF_DIRTYENABLE; - else if (val == CONF_DIRTYDETECTION_OFF) - DUM_CH_CONF(channr) &= ~CONF_DIRTYENABLE; - else - return -EINVAL; - } - - return 0; -} - -EXPORT_SYMBOL(pnx4008_set_dum_channel_dirty_detect); - -#if 0 /* Functions not used currently, but likely to be used in future */ - -static int get_channel(struct dumchannel *p_chan) -{ - int i = p_chan->channelnr; - - if (i < 0 || i > MAX_DUM_CHANNELS) - return -EINVAL; - else { - p_chan->dum_ch_min = DUM_CH_MIN(i); - p_chan->dum_ch_max = DUM_CH_MAX(i); - p_chan->dum_ch_conf = DUM_CH_CONF(i); - p_chan->dum_ch_stat = DUM_CH_STAT(i); - p_chan->dum_ch_ctrl = 0; /* WriteOnly control register */ - } - - return 0; -} - -int pnx4008_get_dum_channel_uf(struct dumchannel_uf *p_chan_uf, int dev_id) -{ - int i = p_chan_uf->channelnr; - - if (i < 0 || i > MAX_DUM_CHANNELS) - return -EINVAL; - else if (dum_data.fb_owning_channel[i] != dev_id) - return -EFBNOTOWNER; - else { - p_chan_uf->dirty = dum_data.chan_uf_store[i].dirty; - p_chan_uf->source = dum_data.chan_uf_store[i].source; - p_chan_uf->x_offset = dum_data.chan_uf_store[i].x_offset; - p_chan_uf->y_offset = dum_data.chan_uf_store[i].y_offset; - p_chan_uf->width = dum_data.chan_uf_store[i].width; - p_chan_uf->height = dum_data.chan_uf_store[i].height; - } - - return 0; -} - -EXPORT_SYMBOL(pnx4008_get_dum_channel_uf); - -int pnx4008_get_dum_channel_config(int channr, int dev_id) -{ - int ret; - struct dumchannel chan; - - if (channr < 0 || channr > MAX_DUM_CHANNELS) - return -EINVAL; - else if (dum_data.fb_owning_channel[channr] != dev_id) - return -EFBNOTOWNER; - else { - chan.channelnr = channr; - if ((ret = get_channel(&chan)) != 0) - return ret; - } - - return (chan.dum_ch_conf & DUM_CHANNEL_CFG_MASK); -} - -EXPORT_SYMBOL(pnx4008_get_dum_channel_config); - -int pnx4008_force_update_dum_channel(int channr, int dev_id) -{ - if (channr < 0 || channr > MAX_DUM_CHANNELS) - return -EINVAL; - - else if (dum_data.fb_owning_channel[channr] != dev_id) - return -EFBNOTOWNER; - else - DUM_CH_CTRL(channr) = CTRL_SETDIRTY; - - return 0; -} - -EXPORT_SYMBOL(pnx4008_force_update_dum_channel); - -#endif - -int pnx4008_sdum_mmap(struct fb_info *info, struct vm_area_struct *vma, - struct device *dev) -{ - unsigned long off = vma->vm_pgoff << PAGE_SHIFT; - - if (off < info->fix.smem_len) { - vma->vm_pgoff += 1; - return dma_mmap_writecombine(dev, vma, - (void *)dum_data.lcd_virt_start, - dum_data.lcd_phys_start, - FB_DMA_SIZE); - } - return -EINVAL; -} - -EXPORT_SYMBOL(pnx4008_sdum_mmap); - -int pnx4008_set_dum_exit_notification(int dev_id) -{ - int i; - - for (i = 0; i < MAX_DUM_CHANNELS; i++) - if (dum_data.fb_owning_channel[i] == dev_id) - return -ERESOURCESNOTFREED; - - return 0; -} - -EXPORT_SYMBOL(pnx4008_set_dum_exit_notification); - -/* Platform device driver for DUM */ - -static int sdum_suspend(struct platform_device *pdev, pm_message_t state) -{ - int retval = 0; - struct clk *clk; - - clk = clk_get(0, "dum_ck"); - if (!IS_ERR(clk)) { - clk_set_rate(clk, 0); - clk_put(clk); - } else - retval = PTR_ERR(clk); - - /* disable BAC */ - DUM_CTRL = V_BAC_DISABLE_IDLE; - - /* LCD standby & turn off display */ - lcd_reset(); - - return retval; -} - -static int sdum_resume(struct platform_device *pdev) -{ - int retval = 0; - struct clk *clk; - - clk = clk_get(0, "dum_ck"); - if (!IS_ERR(clk)) { - clk_set_rate(clk, 1); - clk_put(clk); - } else - retval = PTR_ERR(clk); - - /* wait for BAC disable */ - DUM_CTRL = V_BAC_DISABLE_TRIG; - - while (DUM_CTRL & BAC_ENABLED) - udelay(10); - - /* re-init LCD */ - lcd_init(); - - /* enable BAC and reset MUX */ - DUM_CTRL = V_BAC_ENABLE; - udelay(1); - DUM_CTRL = V_MUX_RESET; - return 0; -} - -static int __devinit sdum_probe(struct platform_device *pdev) -{ - int ret = 0, i = 0; - - /* map frame buffer */ - dum_data.lcd_virt_start = (u32) dma_alloc_writecombine(&pdev->dev, - FB_DMA_SIZE, - &dum_data.lcd_phys_start, - GFP_KERNEL); - - if (!dum_data.lcd_virt_start) { - ret = -ENOMEM; - goto out_3; - } - - /* map slave registers */ - dum_data.slave_phys_base = PNX4008_DUM_SLAVE_BASE; - dum_data.slave_virt_base = - (u32 *) ioremap_nocache(dum_data.slave_phys_base, sizeof(u32)); - - if (dum_data.slave_virt_base == NULL) { - ret = -ENOMEM; - goto out_2; - } - - /* initialize DUM and LCD display */ - ret = dum_init(pdev); - if (ret) - goto out_1; - - dum_chan_init(); - lcd_init(); - - DUM_CTRL = V_BAC_ENABLE; - udelay(1); - DUM_CTRL = V_MUX_RESET; - - /* set decode address and sync clock divider */ - DUM_DECODE = dum_data.lcd_phys_start & DUM_DECODE_MASK; - DUM_CLK_DIV = PNX4008_DUM_CLK_DIV; - - for (i = 0; i < MAX_DUM_CHANNELS; i++) - dum_data.fb_owning_channel[i] = -1; - - /*setup wakeup interrupt */ - start_int_set_rising_edge(SE_DISP_SYNC_INT); - start_int_ack(SE_DISP_SYNC_INT); - start_int_umask(SE_DISP_SYNC_INT); - - return 0; - -out_1: - iounmap((void *)dum_data.slave_virt_base); -out_2: - dma_free_writecombine(&pdev->dev, FB_DMA_SIZE, - (void *)dum_data.lcd_virt_start, - dum_data.lcd_phys_start); -out_3: - return ret; -} - -static int sdum_remove(struct platform_device *pdev) -{ - struct clk *clk; - - start_int_mask(SE_DISP_SYNC_INT); - - clk = clk_get(0, "dum_ck"); - if (!IS_ERR(clk)) { - clk_set_rate(clk, 0); - clk_put(clk); - } - - iounmap((void *)dum_data.slave_virt_base); - - dma_free_writecombine(&pdev->dev, FB_DMA_SIZE, - (void *)dum_data.lcd_virt_start, - dum_data.lcd_phys_start); - - return 0; -} - -static struct platform_driver sdum_driver = { - .driver = { - .name = "pnx4008-sdum", - }, - .probe = sdum_probe, - .remove = sdum_remove, - .suspend = sdum_suspend, - .resume = sdum_resume, -}; - -module_platform_driver(sdum_driver); - -MODULE_LICENSE("GPL"); diff --git a/drivers/video/pnx4008/sdum.h b/drivers/video/pnx4008/sdum.h deleted file mode 100644 index 189c3d641383..000000000000 --- a/drivers/video/pnx4008/sdum.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2005 Philips Semiconductors - * - * 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 Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA, or http://www.gnu.org/licenses/gpl.html -*/ - -#define MAX_DUM_CHANNELS 64 - -#define RGB_MEM_WINDOW(x) (0x10000000 + (x)*0x00100000) - -#define QCIF_OFFSET(x) (((x) == 0) ? 0x00000: ((x) == 1) ? 0x30000: -1) -#define CIF_OFFSET(x) (((x) == 0) ? 0x00000: ((x) == 1) ? 0x60000: -1) - -#define CTRL_SETDIRTY (0x00000001) -#define CONF_DIRTYENABLE (0x00000020) -#define CONF_SYNCENABLE (0x00000004) - -#define DIRTY_ENABLED(conf) ((conf) & 0x0020) -#define SYNC_ENABLED(conf) ((conf) & 0x0004) - -/* Display 1 & 2 Write Timing Configuration */ -#define PNX4008_DUM_WT_CFG 0x00372000 - -/* Display 1 & 2 Read Timing Configuration */ -#define PNX4008_DUM_RT_CFG 0x00003A47 - -/* DUM Transit State Timing Configuration */ -#define PNX4008_DUM_T_CFG 0x1D /* 29 HCLK cycles */ - -/* DUM Sync count clock divider */ -#define PNX4008_DUM_CLK_DIV 0x02DD - -/* Memory size for framebuffer, allocated through dma_alloc_writecombine(). - * Must be PAGE aligned - */ -#define FB_DMA_SIZE (PAGE_ALIGN(SZ_1M + PAGE_SIZE)) - -#define OFFSET_RGBBUFFER (0xB0000) -#define OFFSET_YUVBUFFER (0x00000) - -#define YUVBUFFER (lcd_video_start + OFFSET_YUVBUFFER) -#define RGBBUFFER (lcd_video_start + OFFSET_RGBBUFFER) - -#define CMDSTRING_BASEADDR (0x00C000) /* iram */ -#define BYTES_PER_CMDSTRING (0x80) -#define NR_OF_CMDSTRINGS (64) - -#define MAX_NR_PRESTRINGS (0x40) -#define MAX_NR_POSTSTRINGS (0x40) - -/* various mask definitions */ -#define DUM_CLK_ENABLE 0x01 -#define DUM_CLK_DISABLE 0 -#define DUM_DECODE_MASK 0x1FFFFFFF -#define DUM_CHANNEL_CFG_MASK 0x01FF -#define DUM_CHANNEL_CFG_SYNC_MASK 0xFFFE00FF -#define DUM_CHANNEL_CFG_SYNC_MASK_SET 0x0CA00 - -#define SDUM_RETURNVAL_BASE (0x500) - -#define CONF_SYNC_OFF (0x602) -#define CONF_SYNC_ON (0x603) - -#define CONF_DIRTYDETECTION_OFF (0x600) -#define CONF_DIRTYDETECTION_ON (0x601) - -struct dumchannel_uf { - int channelnr; - u32 *dirty; - u32 *source; - u32 x_offset; - u32 y_offset; - u32 width; - u32 height; -}; - -enum { - FB_TYPE_YUV, - FB_TYPE_RGB -}; - -struct cmdstring { - int channelnr; - uint16_t prestringlen; - uint16_t poststringlen; - uint16_t format; - uint16_t reserved; - uint16_t startaddr_low; - uint16_t startaddr_high; - uint16_t pixdatlen_low; - uint16_t pixdatlen_high; - u32 precmd[MAX_NR_PRESTRINGS]; - u32 postcmd[MAX_NR_POSTSTRINGS]; - -}; - -struct dumchannel { - int channelnr; - int dum_ch_min; - int dum_ch_max; - int dum_ch_conf; - int dum_ch_stat; - int dum_ch_ctrl; -}; - -int pnx4008_alloc_dum_channel(int dev_id); -int pnx4008_free_dum_channel(int channr, int dev_id); - -int pnx4008_get_dum_channel_uf(struct dumchannel_uf *pChan_uf, int dev_id); -int pnx4008_put_dum_channel_uf(struct dumchannel_uf chan_uf, int dev_id); - -int pnx4008_set_dum_channel_sync(int channr, int val, int dev_id); -int pnx4008_set_dum_channel_dirty_detect(int channr, int val, int dev_id); - -int pnx4008_force_dum_update_channel(int channr, int dev_id); - -int pnx4008_get_dum_channel_config(int channr, int dev_id); - -int pnx4008_sdum_mmap(struct fb_info *info, struct vm_area_struct *vma, struct device *dev); -int pnx4008_set_dum_exit_notification(int dev_id); - -int pnx4008_get_fb_addresses(int fb_type, void **virt_addr, - dma_addr_t * phys_addr, int *fb_length); diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 213fbbcf613b..0b340d6ff8a4 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -31,7 +31,6 @@ #include <linux/fb.h> #include <linux/init.h> -#include <asm/abs_addr.h> #include <asm/cell-regs.h> #include <asm/lv1call.h> #include <asm/ps3av.h> @@ -1035,6 +1034,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) if (status) { dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n", __func__, status); + retval = -ENOMEM; goto err_close_device; } dev_dbg(&dev->core, "ddr:lpar:0x%llx\n", ddr_lpar); @@ -1047,6 +1047,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) dev_err(&dev->core, "%s: lv1_gpu_context_allocate failed: %d\n", __func__, status); + retval = -ENOMEM; goto err_gpu_memory_free; } @@ -1054,6 +1055,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024); if (!dinfo) { dev_err(&dev->core, "%s: ioremap failed\n", __func__); + retval = -ENOMEM; goto err_gpu_context_free; } @@ -1122,8 +1124,10 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) } info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core); - if (!info) + if (!info) { + retval = -ENOMEM; goto err_context_fb_close; + } par = info->par; par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */ @@ -1141,7 +1145,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) */ fb_start = ps3fb_videomemory.address + GPU_FB_START; info->screen_base = (char __force __iomem *)fb_start; - info->fix.smem_start = virt_to_abs(fb_start); + info->fix.smem_start = __pa(fb_start); info->fix.smem_len = ps3fb_videomemory.size - GPU_FB_START; info->pseudo_palette = par->pseudo_palette; diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 69bf9d07c237..2ed7b633bbd9 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -25,8 +25,8 @@ #include <linux/interrupt.h> #include <linux/pm_runtime.h> +#include <video/samsung_fimd.h> #include <mach/map.h> -#include <plat/regs-fb-v4.h> #include <plat/fb.h> /* This driver will export a number of framebuffer interfaces depending @@ -1398,35 +1398,28 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) spin_lock_init(&sfb->slock); - sfb->bus_clk = clk_get(dev, "lcd"); + sfb->bus_clk = devm_clk_get(dev, "lcd"); if (IS_ERR(sfb->bus_clk)) { dev_err(dev, "failed to get bus clock\n"); - ret = PTR_ERR(sfb->bus_clk); - goto err_sfb; + return PTR_ERR(sfb->bus_clk); } - clk_enable(sfb->bus_clk); + clk_prepare_enable(sfb->bus_clk); if (!sfb->variant.has_clksel) { - sfb->lcd_clk = clk_get(dev, "sclk_fimd"); + sfb->lcd_clk = devm_clk_get(dev, "sclk_fimd"); if (IS_ERR(sfb->lcd_clk)) { dev_err(dev, "failed to get lcd clock\n"); ret = PTR_ERR(sfb->lcd_clk); goto err_bus_clk; } - clk_enable(sfb->lcd_clk); + clk_prepare_enable(sfb->lcd_clk); } pm_runtime_enable(sfb->dev); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "failed to find registers\n"); - ret = -ENOENT; - goto err_lcd_clk; - } - sfb->regs = devm_request_and_ioremap(dev, res); if (!sfb->regs) { dev_err(dev, "failed to map registers\n"); @@ -1510,16 +1503,12 @@ err_pm_runtime: err_lcd_clk: pm_runtime_disable(sfb->dev); - if (!sfb->variant.has_clksel) { - clk_disable(sfb->lcd_clk); - clk_put(sfb->lcd_clk); - } + if (!sfb->variant.has_clksel) + clk_disable_unprepare(sfb->lcd_clk); err_bus_clk: - clk_disable(sfb->bus_clk); - clk_put(sfb->bus_clk); + clk_disable_unprepare(sfb->bus_clk); -err_sfb: return ret; } @@ -1541,13 +1530,10 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev) if (sfb->windows[win]) s3c_fb_release_win(sfb, sfb->windows[win]); - if (!sfb->variant.has_clksel) { - clk_disable(sfb->lcd_clk); - clk_put(sfb->lcd_clk); - } + if (!sfb->variant.has_clksel) + clk_disable_unprepare(sfb->lcd_clk); - clk_disable(sfb->bus_clk); - clk_put(sfb->bus_clk); + clk_disable_unprepare(sfb->bus_clk); pm_runtime_put_sync(sfb->dev); pm_runtime_disable(sfb->dev); @@ -1575,9 +1561,9 @@ static int s3c_fb_suspend(struct device *dev) } if (!sfb->variant.has_clksel) - clk_disable(sfb->lcd_clk); + clk_disable_unprepare(sfb->lcd_clk); - clk_disable(sfb->bus_clk); + clk_disable_unprepare(sfb->bus_clk); pm_runtime_put_sync(sfb->dev); @@ -1595,10 +1581,10 @@ static int s3c_fb_resume(struct device *dev) pm_runtime_get_sync(sfb->dev); - clk_enable(sfb->bus_clk); + clk_prepare_enable(sfb->bus_clk); if (!sfb->variant.has_clksel) - clk_enable(sfb->lcd_clk); + clk_prepare_enable(sfb->lcd_clk); /* setup gpio and output polarity controls */ pd->setup_gpio(); @@ -1654,9 +1640,9 @@ static int s3c_fb_runtime_suspend(struct device *dev) struct s3c_fb *sfb = platform_get_drvdata(pdev); if (!sfb->variant.has_clksel) - clk_disable(sfb->lcd_clk); + clk_disable_unprepare(sfb->lcd_clk); - clk_disable(sfb->bus_clk); + clk_disable_unprepare(sfb->bus_clk); return 0; } @@ -1667,10 +1653,10 @@ static int s3c_fb_runtime_resume(struct device *dev) struct s3c_fb *sfb = platform_get_drvdata(pdev); struct s3c_fb_platdata *pd = sfb->pdata; - clk_enable(sfb->bus_clk); + clk_prepare_enable(sfb->bus_clk); if (!sfb->variant.has_clksel) - clk_enable(sfb->lcd_clk); + clk_prepare_enable(sfb->lcd_clk); /* setup gpio and output polarity controls */ pd->setup_gpio(); diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 77f34c614c86..1083bb9469ee 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -11,6 +11,8 @@ * Driver based on skeletonfb.c, sa1100fb.c and others. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/kernel.h> #include <linux/err.h> @@ -48,7 +50,11 @@ static int debug = 1; static int debug; #endif -#define dprintk(msg...) if (debug) printk(KERN_DEBUG "s3c2410fb: " msg); +#define dprintk(msg...) \ +do { \ + if (debug) \ + pr_debug(msg); \ +} while (0) /* useful functions */ @@ -598,11 +604,11 @@ static int s3c2410fb_debug_store(struct device *dev, if (strnicmp(buf, "on", 2) == 0 || strnicmp(buf, "1", 1) == 0) { debug = 1; - printk(KERN_DEBUG "s3c2410fb: Debug On"); + dev_dbg(dev, "s3c2410fb: Debug On"); } else if (strnicmp(buf, "off", 3) == 0 || strnicmp(buf, "0", 1) == 0) { debug = 0; - printk(KERN_DEBUG "s3c2410fb: Debug Off"); + dev_dbg(dev, "s3c2410fb: Debug Off"); } else { return -EINVAL; } @@ -921,7 +927,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, info->clk = clk_get(NULL, "lcd"); if (IS_ERR(info->clk)) { - printk(KERN_ERR "failed to get lcd clock source\n"); + dev_err(&pdev->dev, "failed to get lcd clock source\n"); ret = PTR_ERR(info->clk); goto release_irq; } @@ -929,7 +935,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, clk_enable(info->clk); dprintk("got and enabled clock\n"); - usleep_range(1000, 1000); + usleep_range(1000, 1100); info->clk_rate = clk_get_rate(info->clk); @@ -947,7 +953,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, /* Initialize video memory */ ret = s3c2410fb_map_video_memory(fbinfo); if (ret) { - printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret); + dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret); ret = -ENOMEM; goto release_clock; } @@ -970,7 +976,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, ret = register_framebuffer(fbinfo); if (ret < 0) { - printk(KERN_ERR "Failed to register framebuffer device: %d\n", + dev_err(&pdev->dev, "Failed to register framebuffer device: %d\n", ret); goto free_cpufreq; } @@ -978,9 +984,9 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, /* create device files */ ret = device_create_file(&pdev->dev, &dev_attr_debug); if (ret) - printk(KERN_ERR "failed to add debug attribute\n"); + dev_err(&pdev->dev, "failed to add debug attribute\n"); - printk(KERN_INFO "fb%d: %s frame buffer device\n", + dev_info(&pdev->dev, "fb%d: %s frame buffer device\n", fbinfo->node, fbinfo->fix.id); return 0; @@ -1028,7 +1034,7 @@ static int __devexit s3c2410fb_remove(struct platform_device *pdev) s3c2410fb_cpufreq_deregister(info); s3c2410fb_lcd_enable(info, 0); - usleep_range(1000, 1000); + usleep_range(1000, 1100); s3c2410fb_unmap_video_memory(fbinfo); @@ -1065,7 +1071,7 @@ static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state) * the LCD DMA engine is not going to get back on the bus * before the clock goes off again (bjd) */ - usleep_range(1000, 1000); + usleep_range(1000, 1100); clk_disable(info->clk); return 0; @@ -1077,7 +1083,7 @@ static int s3c2410fb_resume(struct platform_device *dev) struct s3c2410fb_info *info = fbinfo->par; clk_enable(info->clk); - usleep_range(1000, 1000); + usleep_range(1000, 1100); s3c2410fb_init_registers(fbinfo); @@ -1134,8 +1140,8 @@ static void __exit s3c2410fb_cleanup(void) module_init(s3c2410fb_init); module_exit(s3c2410fb_cleanup); -MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, " - "Ben Dooks <ben-linux@fluff.org>"); +MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); +MODULE_AUTHOR("Ben Dooks <ben-linux@fluff.org>"); MODULE_DESCRIPTION("Framebuffer driver for the s3c2410"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:s3c2410-lcd"); diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 0d0f52c18fd8..f4f53b082d05 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c @@ -2266,8 +2266,10 @@ static int __devinit savagefb_probe(struct pci_dev* dev, lpitch = info->var.xres_virtual*((info->var.bits_per_pixel + 7) >> 3); info->var.yres_virtual = info->fix.smem_len/lpitch; - if (info->var.yres_virtual < info->var.yres) + if (info->var.yres_virtual < info->var.yres) { + err = -ENOMEM; goto failed; + } #if defined(CONFIG_FB_SAVAGE_ACCEL) /* diff --git a/drivers/video/sbuslib.c b/drivers/video/sbuslib.c index 3c1de981a18c..296afae442f4 100644 --- a/drivers/video/sbuslib.c +++ b/drivers/video/sbuslib.c @@ -57,9 +57,8 @@ int sbusfb_mmap_helper(struct sbus_mmap_map *map, off = vma->vm_pgoff << PAGE_SHIFT; - /* To stop the swapper from even considering these pages */ - vma->vm_flags |= (VM_IO | VM_RESERVED); - + /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* Each page, see which map applies */ diff --git a/drivers/video/sis/initextlfb.c b/drivers/video/sis/initextlfb.c index 9dec64da4015..3ab18f5a3759 100644 --- a/drivers/video/sis/initextlfb.c +++ b/drivers/video/sis/initextlfb.c @@ -65,7 +65,7 @@ sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, unsigned char modeno, } #endif - if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) {; + if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) { printk(KERN_ERR "Could not find mode %x\n", ModeNo); return 65000; } diff --git a/drivers/video/smscufx.c b/drivers/video/smscufx.c index 5533a32c6ca1..97bd6620c364 100644 --- a/drivers/video/smscufx.c +++ b/drivers/video/smscufx.c @@ -803,7 +803,6 @@ static int ufx_ops_mmap(struct fb_info *info, struct vm_area_struct *vma) size = 0; } - vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ return 0; } diff --git a/drivers/video/sunxvr1000.c b/drivers/video/sunxvr1000.c index b7f27acaf817..729a50722bdf 100644 --- a/drivers/video/sunxvr1000.c +++ b/drivers/video/sunxvr1000.c @@ -141,8 +141,10 @@ static int __devinit gfb_probe(struct platform_device *op) gp->fb_base = of_ioremap(&op->resource[6], 0, gp->fb_size, "gfb fb"); - if (!gp->fb_base) + if (!gp->fb_base) { + err = -ENOMEM; goto err_release_fb; + } err = gfb_set_fbinfo(gp); if (err) diff --git a/drivers/video/sunxvr2500.c b/drivers/video/sunxvr2500.c index 5848436c19da..7fbcba86d1a2 100644 --- a/drivers/video/sunxvr2500.c +++ b/drivers/video/sunxvr2500.c @@ -181,8 +181,10 @@ static int __devinit s3d_pci_register(struct pci_dev *pdev, sp->fb_size = info->fix.line_length * sp->height; sp->fb_base = ioremap(sp->fb_base_phys, sp->fb_size); - if (!sp->fb_base) + if (!sp->fb_base) { + err = -ENOMEM; goto err_release_pci; + } err = s3d_set_fbinfo(sp); if (err) diff --git a/drivers/video/sunxvr500.c b/drivers/video/sunxvr500.c index eb931b8626fa..6c71b1b44477 100644 --- a/drivers/video/sunxvr500.c +++ b/drivers/video/sunxvr500.c @@ -298,8 +298,10 @@ static int __devinit e3d_pci_register(struct pci_dev *pdev, goto err_release_fb; } ep->ramdac = ioremap(ep->regs_base_phys + 0x8000, 0x1000); - if (!ep->ramdac) + if (!ep->ramdac) { + err = -ENOMEM; goto err_release_pci1; + } ep->fb8_0_off = readl(ep->ramdac + RAMDAC_VID_8FB_0); ep->fb8_0_off -= ep->fb_base_reg; @@ -343,8 +345,10 @@ static int __devinit e3d_pci_register(struct pci_dev *pdev, ep->fb_size = info->fix.line_length * ep->height; ep->fb_base = ioremap(ep->fb_base_phys, ep->fb_size); - if (!ep->fb_base) + if (!ep->fb_base) { + err = -ENOMEM; goto err_release_pci0; + } err = e3d_set_fbinfo(ep); if (err) diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c index 8af64148294b..86d449ea3169 100644 --- a/drivers/video/udlfb.c +++ b/drivers/video/udlfb.c @@ -345,7 +345,6 @@ static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma) size = 0; } - vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ return 0; } @@ -647,7 +646,7 @@ static ssize_t dlfb_ops_write(struct fb_info *info, const char __user *buf, result = fb_sys_write(info, buf, count, ppos); if (result > 0) { - int start = max((int)(offset / info->fix.line_length) - 1, 0); + int start = max((int)(offset / info->fix.line_length), 0); int lines = min((u32)((result / info->fix.line_length) + 1), (u32)info->var.yres); diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index b0e2a4261afe..2f8f82d874a1 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -659,6 +659,8 @@ static int __devinit uvesafb_vbe_getedid(struct uvesafb_ktask *task, task->t.flags = TF_BUF_RET | TF_BUF_ESDI; task->t.buf_len = EDID_LENGTH; task->buf = kzalloc(EDID_LENGTH, GFP_KERNEL); + if (!task->buf) + return -ENOMEM; err = uvesafb_exec(task); diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c index 970e43d13f52..4709edc3cb7f 100644 --- a/drivers/video/vermilion/vermilion.c +++ b/drivers/video/vermilion/vermilion.c @@ -1018,7 +1018,6 @@ static int vmlfb_mmap(struct fb_info *info, struct vm_area_struct *vma) offset += vinfo->vram_start; pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT; - vma->vm_flags |= VM_RESERVED | VM_IO; if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT, size, vma->vm_page_prot)) return -EAGAIN; @@ -1168,8 +1167,7 @@ void vmlfb_unregister_subsys(struct vml_sys *sys) list_for_each_entry_safe(entry, next, &global_has_mode, head) { printk(KERN_DEBUG MODULE_NAME ": subsys disable pipe\n"); vmlfb_disable_pipe(entry); - list_del(&entry->head); - list_add_tail(&entry->head, &global_no_mode); + list_move_tail(&entry->head, &global_no_mode); } mutex_unlock(&vml_mutex); } diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index 501a922aa9dc..c7f692525b88 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c @@ -439,7 +439,6 @@ static int vfb_mmap(struct fb_info *info, size = 0; } - vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ return 0; } diff --git a/drivers/video/via/via_clock.c b/drivers/video/via/via_clock.c index af8f26b643c1..db1e39277e32 100644 --- a/drivers/video/via/via_clock.c +++ b/drivers/video/via/via_clock.c @@ -25,6 +25,7 @@ #include <linux/kernel.h> #include <linux/via-core.h> +#include <asm/olpc.h> #include "via_clock.h" #include "global.h" #include "debug.h" @@ -289,6 +290,10 @@ static void dummy_set_pll(struct via_pll_config config) printk(KERN_INFO "Using undocumented set PLL.\n%s", via_slap); } +static void noop_set_clock_state(u8 state) +{ +} + void via_clock_init(struct via_clock *clock, int gfx_chip) { switch (gfx_chip) { @@ -346,4 +351,18 @@ void via_clock_init(struct via_clock *clock, int gfx_chip) break; } + + if (machine_is_olpc()) { + /* The OLPC XO-1.5 cannot suspend/resume reliably if the + * IGA1/IGA2 clocks are set as on or off (memory rot + * occasionally happens during suspend under such + * configurations). + * + * The only known stable scenario is to leave this bits as-is, + * which in their default states are documented to enable the + * clock only when it is needed. + */ + clock->set_primary_clock_state = noop_set_clock_state; + clock->set_secondary_clock_state = noop_set_clock_state; + } } |