diff options
Diffstat (limited to 'drivers/video')
80 files changed, 2432 insertions, 388 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index bb5fbed89e7..5a5c303a637 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -614,6 +614,21 @@ config FB_BFIN_T350MCQB This display is a QVGA 320x240 24-bit RGB display interfaced by an 8-bit wide PPI It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK. +config FB_BFIN_LQ035Q1 + tristate "SHARP LQ035Q1DH02 TFT LCD" + depends on FB && BLACKFIN && SPI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select BFIN_GPTIMERS + help + This is the framebuffer device driver for a SHARP LQ035Q1DH02 TFT display found on + the Blackfin Landscape LCD EZ-Extender Card. + This display is a QVGA 320x240 18-bit RGB display interfaced by an 16-bit wide PPI + It uses PPI[0..15] PPI_FS1, PPI_FS2 and PPI_CLK. + + To compile this driver as a module, choose M here: the + module will be called bfin-lq035q1-fb. config FB_STI tristate "HP STI frame buffer device support" @@ -2131,7 +2146,7 @@ config FB_PRE_INIT_FB the bootloader. config FB_MSM - tristate + tristate "MSM Framebuffer support" depends on FB && ARCH_MSM select FB_CFB_FILLRECT select FB_CFB_COPYAREA diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 0f8da331ba0..4ecb30c4f3f 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -137,6 +137,7 @@ obj-$(CONFIG_FB_EFI) += efifb.o obj-$(CONFIG_FB_VGA16) += vga16fb.o obj-$(CONFIG_FB_OF) += offb.o obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o +obj-$(CONFIG_FB_BFIN_LQ035Q1) += bfin-lq035q1-fb.o obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o obj-$(CONFIG_FB_MX3) += mx3fb.o obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c index ad05da5ba3c..86d95c228ad 100644 --- a/drivers/video/backlight/adp5520_bl.c +++ b/drivers/video/backlight/adp5520_bl.c @@ -15,7 +15,7 @@ struct adp5520_bl { struct device *master; - struct adp5520_backlight_platfrom_data *pdata; + struct adp5520_backlight_platform_data *pdata; struct mutex lock; unsigned long cached_daylight_max; int id; @@ -31,29 +31,30 @@ static int adp5520_bl_set(struct backlight_device *bl, int brightness) if (data->pdata->en_ambl_sens) { if ((brightness > 0) && (brightness < ADP5020_MAX_BRIGHTNESS)) { /* Disable Ambient Light auto adjust */ - ret |= adp5520_clr_bits(master, BL_CONTROL, - BL_AUTO_ADJ); - ret |= adp5520_write(master, DAYLIGHT_MAX, brightness); + ret |= adp5520_clr_bits(master, ADP5520_BL_CONTROL, + ADP5520_BL_AUTO_ADJ); + ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX, + brightness); } else { /* * MAX_BRIGHTNESS -> Enable Ambient Light auto adjust * restore daylight l3 sysfs brightness */ - ret |= adp5520_write(master, DAYLIGHT_MAX, + ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX, data->cached_daylight_max); - ret |= adp5520_set_bits(master, BL_CONTROL, - BL_AUTO_ADJ); + ret |= adp5520_set_bits(master, ADP5520_BL_CONTROL, + ADP5520_BL_AUTO_ADJ); } } else { - ret |= adp5520_write(master, DAYLIGHT_MAX, brightness); + ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX, brightness); } if (data->current_brightness && brightness == 0) ret |= adp5520_set_bits(master, - MODE_STATUS, DIM_EN); + ADP5520_MODE_STATUS, ADP5520_DIM_EN); else if (data->current_brightness == 0 && brightness) ret |= adp5520_clr_bits(master, - MODE_STATUS, DIM_EN); + ADP5520_MODE_STATUS, ADP5520_DIM_EN); if (!ret) data->current_brightness = brightness; @@ -79,12 +80,12 @@ static int adp5520_bl_get_brightness(struct backlight_device *bl) int error; uint8_t reg_val; - error = adp5520_read(data->master, BL_VALUE, ®_val); + error = adp5520_read(data->master, ADP5520_BL_VALUE, ®_val); return error ? data->current_brightness : reg_val; } -static struct backlight_ops adp5520_bl_ops = { +static const struct backlight_ops adp5520_bl_ops = { .update_status = adp5520_bl_update_status, .get_brightness = adp5520_bl_get_brightness, }; @@ -93,33 +94,46 @@ static int adp5520_bl_setup(struct backlight_device *bl) { struct adp5520_bl *data = bl_get_data(bl); struct device *master = data->master; - struct adp5520_backlight_platfrom_data *pdata = data->pdata; + struct adp5520_backlight_platform_data *pdata = data->pdata; int ret = 0; - ret |= adp5520_write(master, DAYLIGHT_MAX, pdata->l1_daylight_max); - ret |= adp5520_write(master, DAYLIGHT_DIM, pdata->l1_daylight_dim); + ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX, + pdata->l1_daylight_max); + ret |= adp5520_write(master, ADP5520_DAYLIGHT_DIM, + pdata->l1_daylight_dim); if (pdata->en_ambl_sens) { data->cached_daylight_max = pdata->l1_daylight_max; - ret |= adp5520_write(master, OFFICE_MAX, pdata->l2_office_max); - ret |= adp5520_write(master, OFFICE_DIM, pdata->l2_office_dim); - ret |= adp5520_write(master, DARK_MAX, pdata->l3_dark_max); - ret |= adp5520_write(master, DARK_DIM, pdata->l3_dark_dim); - ret |= adp5520_write(master, L2_TRIP, pdata->l2_trip); - ret |= adp5520_write(master, L2_HYS, pdata->l2_hyst); - ret |= adp5520_write(master, L3_TRIP, pdata->l3_trip); - ret |= adp5520_write(master, L3_HYS, pdata->l3_hyst); - ret |= adp5520_write(master, ALS_CMPR_CFG, - ALS_CMPR_CFG_VAL(pdata->abml_filt, L3_EN)); + ret |= adp5520_write(master, ADP5520_OFFICE_MAX, + pdata->l2_office_max); + ret |= adp5520_write(master, ADP5520_OFFICE_DIM, + pdata->l2_office_dim); + ret |= adp5520_write(master, ADP5520_DARK_MAX, + pdata->l3_dark_max); + ret |= adp5520_write(master, ADP5520_DARK_DIM, + pdata->l3_dark_dim); + ret |= adp5520_write(master, ADP5520_L2_TRIP, + pdata->l2_trip); + ret |= adp5520_write(master, ADP5520_L2_HYS, + pdata->l2_hyst); + ret |= adp5520_write(master, ADP5520_L3_TRIP, + pdata->l3_trip); + ret |= adp5520_write(master, ADP5520_L3_HYS, + pdata->l3_hyst); + ret |= adp5520_write(master, ADP5520_ALS_CMPR_CFG, + ALS_CMPR_CFG_VAL(pdata->abml_filt, + ADP5520_L3_EN)); } - ret |= adp5520_write(master, BL_CONTROL, - BL_CTRL_VAL(pdata->fade_led_law, pdata->en_ambl_sens)); + ret |= adp5520_write(master, ADP5520_BL_CONTROL, + BL_CTRL_VAL(pdata->fade_led_law, + pdata->en_ambl_sens)); - ret |= adp5520_write(master, BL_FADE, FADE_VAL(pdata->fade_in, + ret |= adp5520_write(master, ADP5520_BL_FADE, FADE_VAL(pdata->fade_in, pdata->fade_out)); - ret |= adp5520_set_bits(master, MODE_STATUS, BL_EN | DIM_EN); + ret |= adp5520_set_bits(master, ADP5520_MODE_STATUS, + ADP5520_BL_EN | ADP5520_DIM_EN); return ret; } @@ -156,29 +170,31 @@ static ssize_t adp5520_store(struct device *dev, const char *buf, } static ssize_t adp5520_bl_dark_max_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { - return adp5520_show(dev, buf, DARK_MAX); + return adp5520_show(dev, buf, ADP5520_DARK_MAX); } static ssize_t adp5520_bl_dark_max_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) + struct device_attribute *attr, + const char *buf, size_t count) { - return adp5520_store(dev, buf, count, DARK_MAX); + return adp5520_store(dev, buf, count, ADP5520_DARK_MAX); } static DEVICE_ATTR(dark_max, 0664, adp5520_bl_dark_max_show, adp5520_bl_dark_max_store); static ssize_t adp5520_bl_office_max_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { - return adp5520_show(dev, buf, OFFICE_MAX); + return adp5520_show(dev, buf, ADP5520_OFFICE_MAX); } static ssize_t adp5520_bl_office_max_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) + struct device_attribute *attr, + const char *buf, size_t count) { - return adp5520_store(dev, buf, count, OFFICE_MAX); + return adp5520_store(dev, buf, count, ADP5520_OFFICE_MAX); } static DEVICE_ATTR(office_max, 0664, adp5520_bl_office_max_show, adp5520_bl_office_max_store); @@ -186,16 +202,17 @@ static DEVICE_ATTR(office_max, 0664, adp5520_bl_office_max_show, static ssize_t adp5520_bl_daylight_max_show(struct device *dev, struct device_attribute *attr, char *buf) { - return adp5520_show(dev, buf, DAYLIGHT_MAX); + return adp5520_show(dev, buf, ADP5520_DAYLIGHT_MAX); } static ssize_t adp5520_bl_daylight_max_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) + struct device_attribute *attr, + const char *buf, size_t count) { struct adp5520_bl *data = dev_get_drvdata(dev); strict_strtoul(buf, 10, &data->cached_daylight_max); - return adp5520_store(dev, buf, count, DAYLIGHT_MAX); + return adp5520_store(dev, buf, count, ADP5520_DAYLIGHT_MAX); } static DEVICE_ATTR(daylight_max, 0664, adp5520_bl_daylight_max_show, adp5520_bl_daylight_max_store); @@ -203,14 +220,14 @@ static DEVICE_ATTR(daylight_max, 0664, adp5520_bl_daylight_max_show, static ssize_t adp5520_bl_dark_dim_show(struct device *dev, struct device_attribute *attr, char *buf) { - return adp5520_show(dev, buf, DARK_DIM); + return adp5520_show(dev, buf, ADP5520_DARK_DIM); } static ssize_t adp5520_bl_dark_dim_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) + struct device_attribute *attr, + const char *buf, size_t count) { - return adp5520_store(dev, buf, count, DARK_DIM); + return adp5520_store(dev, buf, count, ADP5520_DARK_DIM); } static DEVICE_ATTR(dark_dim, 0664, adp5520_bl_dark_dim_show, adp5520_bl_dark_dim_store); @@ -218,29 +235,29 @@ static DEVICE_ATTR(dark_dim, 0664, adp5520_bl_dark_dim_show, static ssize_t adp5520_bl_office_dim_show(struct device *dev, struct device_attribute *attr, char *buf) { - return adp5520_show(dev, buf, OFFICE_DIM); + return adp5520_show(dev, buf, ADP5520_OFFICE_DIM); } static ssize_t adp5520_bl_office_dim_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) + struct device_attribute *attr, + const char *buf, size_t count) { - return adp5520_store(dev, buf, count, OFFICE_DIM); + return adp5520_store(dev, buf, count, ADP5520_OFFICE_DIM); } static DEVICE_ATTR(office_dim, 0664, adp5520_bl_office_dim_show, adp5520_bl_office_dim_store); static ssize_t adp5520_bl_daylight_dim_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, char *buf) { - return adp5520_show(dev, buf, DAYLIGHT_DIM); + return adp5520_show(dev, buf, ADP5520_DAYLIGHT_DIM); } static ssize_t adp5520_bl_daylight_dim_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) + struct device_attribute *attr, + const char *buf, size_t count) { - return adp5520_store(dev, buf, count, DAYLIGHT_DIM); + return adp5520_store(dev, buf, count, ADP5520_DAYLIGHT_DIM); } static DEVICE_ATTR(daylight_dim, 0664, adp5520_bl_daylight_dim_show, adp5520_bl_daylight_dim_store); @@ -316,7 +333,7 @@ static int __devexit adp5520_bl_remove(struct platform_device *pdev) struct backlight_device *bl = platform_get_drvdata(pdev); struct adp5520_bl *data = bl_get_data(bl); - adp5520_clr_bits(data->master, MODE_STATUS, BL_EN); + adp5520_clr_bits(data->master, ADP5520_MODE_STATUS, ADP5520_BL_EN); if (data->pdata->en_ambl_sens) sysfs_remove_group(&bl->dev.kobj, diff --git a/drivers/video/backlight/adx_bl.c b/drivers/video/backlight/adx_bl.c index 2c3bdfc620b..d769b0bab21 100644 --- a/drivers/video/backlight/adx_bl.c +++ b/drivers/video/backlight/adx_bl.c @@ -61,7 +61,7 @@ static int adx_backlight_check_fb(struct fb_info *fb) return 1; } -static struct backlight_ops adx_backlight_ops = { +static const struct backlight_ops adx_backlight_ops = { .options = 0, .update_status = adx_backlight_update_status, .get_brightness = adx_backlight_get_brightness, diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c index 2cf7ba52f67..f625ffc69ad 100644 --- a/drivers/video/backlight/atmel-pwm-bl.c +++ b/drivers/video/backlight/atmel-pwm-bl.c @@ -113,7 +113,7 @@ static int atmel_pwm_bl_init_pwm(struct atmel_pwm_bl *pwmbl) return pwm_channel_enable(&pwmbl->pwmc); } -static struct backlight_ops atmel_pwm_bl_ops = { +static const struct backlight_ops atmel_pwm_bl_ops = { .get_brightness = atmel_pwm_bl_get_intensity, .update_status = atmel_pwm_bl_set_intensity, }; diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 6615ac7fa60..18829cf68b1 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -269,7 +269,7 @@ EXPORT_SYMBOL(backlight_force_update); * ERR_PTR() or a pointer to the newly allocated device. */ struct backlight_device *backlight_device_register(const char *name, - struct device *parent, void *devdata, struct backlight_ops *ops) + struct device *parent, void *devdata, const struct backlight_ops *ops) { struct backlight_device *new_bd; int rc; diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c index 96774949cd3..b4bcf804379 100644 --- a/drivers/video/backlight/corgi_lcd.c +++ b/drivers/video/backlight/corgi_lcd.c @@ -451,7 +451,7 @@ void corgi_lcd_limit_intensity(int limit) } EXPORT_SYMBOL(corgi_lcd_limit_intensity); -static struct backlight_ops corgi_bl_ops = { +static const struct backlight_ops corgi_bl_ops = { .get_brightness = corgi_bl_get_intensity, .update_status = corgi_bl_update_status, }; diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c index b9fe62b475c..da86db4374a 100644 --- a/drivers/video/backlight/cr_bllcd.c +++ b/drivers/video/backlight/cr_bllcd.c @@ -108,7 +108,7 @@ static int cr_backlight_get_intensity(struct backlight_device *bd) return intensity; } -static struct backlight_ops cr_backlight_ops = { +static const struct backlight_ops cr_backlight_ops = { .get_brightness = cr_backlight_get_intensity, .update_status = cr_backlight_set_intensity, }; @@ -201,7 +201,7 @@ static int cr_backlight_probe(struct platform_device *pdev) if (IS_ERR(ldp)) { backlight_device_unregister(bdp); pci_dev_put(lpc_dev); - return PTR_ERR(bdp); + return PTR_ERR(ldp); } pci_read_config_dword(lpc_dev, CRVML_REG_GPIOBAR, diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c index 7fcb0eb54c6..74cdc640173 100644 --- a/drivers/video/backlight/da903x_bl.c +++ b/drivers/video/backlight/da903x_bl.c @@ -95,7 +95,7 @@ static int da903x_backlight_get_brightness(struct backlight_device *bl) return data->current_brightness; } -static struct backlight_ops da903x_backlight_ops = { +static const struct backlight_ops da903x_backlight_ops = { .update_status = da903x_backlight_update_status, .get_brightness = da903x_backlight_get_brightness, }; @@ -177,7 +177,7 @@ static int da903x_backlight_resume(struct device *dev) return 0; } -static struct dev_pm_ops da903x_backlight_pm_ops = { +static const struct dev_pm_ops da903x_backlight_pm_ops = { .suspend = da903x_backlight_suspend, .resume = da903x_backlight_resume, }; diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c index 6d27f62fdcd..e6d348e6359 100644 --- a/drivers/video/backlight/generic_bl.c +++ b/drivers/video/backlight/generic_bl.c @@ -70,7 +70,7 @@ void corgibl_limit_intensity(int limit) } EXPORT_SYMBOL(corgibl_limit_intensity); -static struct backlight_ops genericbl_ops = { +static const struct backlight_ops genericbl_ops = { .options = BL_CORE_SUSPENDRESUME, .get_brightness = genericbl_get_intensity, .update_status = genericbl_send_intensity, diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index 7fb4eefff80..f7cc528d5be 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -98,7 +98,7 @@ static int hp680bl_get_intensity(struct backlight_device *bd) return current_intensity; } -static struct backlight_ops hp680bl_ops = { +static const struct backlight_ops hp680bl_ops = { .get_brightness = hp680bl_get_intensity, .update_status = hp680bl_set_intensity, }; diff --git a/drivers/video/backlight/jornada720_bl.c b/drivers/video/backlight/jornada720_bl.c index 7aed2565c1b..db9071fc566 100644 --- a/drivers/video/backlight/jornada720_bl.c +++ b/drivers/video/backlight/jornada720_bl.c @@ -93,7 +93,7 @@ out: return ret; } -static struct backlight_ops jornada_bl_ops = { +static const struct backlight_ops jornada_bl_ops = { .get_brightness = jornada_bl_get_brightness, .update_status = jornada_bl_update_status, .options = BL_CORE_SUSPENDRESUME, diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c index a38fda1742d..939e7b830cf 100644 --- a/drivers/video/backlight/kb3886_bl.c +++ b/drivers/video/backlight/kb3886_bl.c @@ -134,7 +134,7 @@ static int kb3886bl_get_intensity(struct backlight_device *bd) return kb3886bl_intensity; } -static struct backlight_ops kb3886bl_ops = { +static const struct backlight_ops kb3886bl_ops = { .get_brightness = kb3886bl_get_intensity, .update_status = kb3886bl_send_intensity, }; diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index a482dd7b031..9b3be74cee5 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -101,7 +101,7 @@ static ssize_t lcd_store_power(struct device *dev, int power = simple_strtoul(buf, &endp, 0); size_t size = endp - buf; - if (*endp && isspace(*endp)) + if (isspace(*endp)) size++; if (size != count) return -EINVAL; @@ -140,7 +140,7 @@ static ssize_t lcd_store_contrast(struct device *dev, int contrast = simple_strtoul(buf, &endp, 0); size_t size = endp - buf; - if (*endp && isspace(*endp)) + if (isspace(*endp)) size++; if (size != count) return -EINVAL; diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c index 6b488b8a7ee..00a9591b000 100644 --- a/drivers/video/backlight/locomolcd.c +++ b/drivers/video/backlight/locomolcd.c @@ -141,7 +141,7 @@ static int locomolcd_get_intensity(struct backlight_device *bd) return current_intensity; } -static struct backlight_ops locomobl_data = { +static const struct backlight_ops locomobl_data = { .get_brightness = locomolcd_get_intensity, .update_status = locomolcd_set_intensity, }; diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c index 9edb8d7c295..2e78b0784bd 100644 --- a/drivers/video/backlight/mbp_nvidia_bl.c +++ b/drivers/video/backlight/mbp_nvidia_bl.c @@ -33,7 +33,7 @@ struct dmi_match_data { unsigned long iostart; unsigned long iolen; /* Backlight operations structure. */ - struct backlight_ops backlight_ops; + const struct backlight_ops backlight_ops; }; /* Module parameters. */ @@ -220,6 +220,24 @@ static const struct dmi_system_id __initdata mbp_device_table[] = { }, { .callback = mbp_dmi_match, + .ident = "MacBookPro 5,3", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3"), + }, + .driver_data = (void *)&nvidia_chipset_data, + }, + { + .callback = mbp_dmi_match, + .ident = "MacBookPro 5,4", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4"), + }, + .driver_data = (void *)&nvidia_chipset_data, + }, + { + .callback = mbp_dmi_match, .ident = "MacBookPro 5,5", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c index 8693e5fcd2e..a3a7f893817 100644 --- a/drivers/video/backlight/omap1_bl.c +++ b/drivers/video/backlight/omap1_bl.c @@ -125,7 +125,7 @@ static int omapbl_get_intensity(struct backlight_device *dev) return bl->current_intensity; } -static struct backlight_ops omapbl_ops = { +static const struct backlight_ops omapbl_ops = { .get_brightness = omapbl_get_intensity, .update_status = omapbl_update_status, }; @@ -139,8 +139,6 @@ static int omapbl_probe(struct platform_device *pdev) if (!pdata) return -ENXIO; - omapbl_ops.check_fb = pdata->check_fb; - bl = kzalloc(sizeof(struct omap_backlight), GFP_KERNEL); if (unlikely(!bl)) return -ENOMEM; diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c index 9edaf24fd82..075786e0503 100644 --- a/drivers/video/backlight/progear_bl.c +++ b/drivers/video/backlight/progear_bl.c @@ -54,7 +54,7 @@ static int progearbl_get_intensity(struct backlight_device *bd) return intensity - HW_LEVEL_MIN; } -static struct backlight_ops progearbl_ops = { +static const struct backlight_ops progearbl_ops = { .get_brightness = progearbl_get_intensity, .update_status = progearbl_set_intensity, }; diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 88716626744..9d2ec2a1cce 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -22,8 +22,10 @@ struct pwm_bl_data { struct pwm_device *pwm; + struct device *dev; unsigned int period; - int (*notify)(int brightness); + int (*notify)(struct device *, + int brightness); }; static int pwm_backlight_update_status(struct backlight_device *bl) @@ -39,7 +41,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl) brightness = 0; if (pb->notify) - brightness = pb->notify(brightness); + brightness = pb->notify(pb->dev, brightness); if (brightness == 0) { pwm_config(pb->pwm, 0, pb->period); @@ -56,7 +58,7 @@ static int pwm_backlight_get_brightness(struct backlight_device *bl) return bl->props.brightness; } -static struct backlight_ops pwm_backlight_ops = { +static const struct backlight_ops pwm_backlight_ops = { .update_status = pwm_backlight_update_status, .get_brightness = pwm_backlight_get_brightness, }; @@ -88,6 +90,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) pb->period = data->pwm_period_ns; pb->notify = data->notify; + pb->dev = &pdev->dev; pb->pwm = pwm_request(data->pwm_id, "backlight"); if (IS_ERR(pb->pwm)) { @@ -146,7 +149,7 @@ static int pwm_backlight_suspend(struct platform_device *pdev, struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev); if (pb->notify) - pb->notify(0); + pb->notify(pb->dev, 0); pwm_config(pb->pwm, 0, pb->period); pwm_disable(pb->pwm); return 0; diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c index 43edbada12d..e14ce4d469f 100644 --- a/drivers/video/backlight/tosa_bl.c +++ b/drivers/video/backlight/tosa_bl.c @@ -72,7 +72,7 @@ static int tosa_bl_get_brightness(struct backlight_device *dev) return props->brightness; } -static struct backlight_ops bl_ops = { +static const struct backlight_ops bl_ops = { .get_brightness = tosa_bl_get_brightness, .update_status = tosa_bl_update_status, }; diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c index 467bdb7efb2..e32add37a20 100644 --- a/drivers/video/backlight/wm831x_bl.c +++ b/drivers/video/backlight/wm831x_bl.c @@ -112,7 +112,7 @@ static int wm831x_backlight_get_brightness(struct backlight_device *bl) return data->current_brightness; } -static struct backlight_ops wm831x_backlight_ops = { +static const struct backlight_ops wm831x_backlight_ops = { .options = BL_CORE_SUSPENDRESUME, .update_status = wm831x_backlight_update_status, .get_brightness = wm831x_backlight_get_brightness, diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c new file mode 100644 index 00000000000..b690c269784 --- /dev/null +++ b/drivers/video/bfin-lq035q1-fb.c @@ -0,0 +1,826 @@ +/* + * Blackfin LCD Framebuffer driver SHARP LQ035Q1DH02 + * + * Copyright 2008-2009 Analog Devices Inc. + * Licensed under the GPL-2 or later. + */ + +#define DRIVER_NAME "bfin-lq035q1" +#define pr_fmt(fmt) DRIVER_NAME ": " fmt + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/backlight.h> +#include <linux/lcd.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/dma-mapping.h> + +#include <asm/blackfin.h> +#include <asm/irq.h> +#include <asm/dma.h> +#include <asm/portmux.h> +#include <asm/gptimers.h> + +#include <asm/bfin-lq035q1.h> + +#if defined(BF533_FAMILY) || defined(BF538_FAMILY) +#define TIMER_HSYNC_id TIMER1_id +#define TIMER_HSYNCbit TIMER1bit +#define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN1 +#define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1 +#define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF1 + +#define TIMER_VSYNC_id TIMER2_id +#define TIMER_VSYNCbit TIMER2bit +#define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN2 +#define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL2 +#define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF2 +#else +#define TIMER_HSYNC_id TIMER0_id +#define TIMER_HSYNCbit TIMER0bit +#define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN0 +#define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL0 +#define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF0 + +#define TIMER_VSYNC_id TIMER1_id +#define TIMER_VSYNCbit TIMER1bit +#define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN1 +#define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1 +#define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF1 +#endif + +#define LCD_X_RES 320 /* Horizontal Resolution */ +#define LCD_Y_RES 240 /* Vertical Resolution */ +#define DMA_BUS_SIZE 16 + +#define USE_RGB565_16_BIT_PPI + +#ifdef USE_RGB565_16_BIT_PPI +#define LCD_BPP 16 /* Bit Per Pixel */ +#define CLOCKS_PER_PIX 1 +#define CPLD_PIPELINE_DELAY_COR 0 /* NO CPLB */ +#endif + +/* Interface 16/18-bit TFT over an 8-bit wide PPI using a small Programmable Logic Device (CPLD) + * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165 + */ + +#ifdef USE_RGB565_8_BIT_PPI +#define LCD_BPP 16 /* Bit Per Pixel */ +#define CLOCKS_PER_PIX 2 +#define CPLD_PIPELINE_DELAY_COR 3 /* RGB565 */ +#endif + +#ifdef USE_RGB888_8_BIT_PPI +#define LCD_BPP 24 /* Bit Per Pixel */ +#define CLOCKS_PER_PIX 3 +#define CPLD_PIPELINE_DELAY_COR 5 /* RGB888 */ +#endif + + /* + * HS and VS timing parameters (all in number of PPI clk ticks) + */ + +#define U_LINE 4 /* Blanking Lines */ + +#define H_ACTPIX (LCD_X_RES * CLOCKS_PER_PIX) /* active horizontal pixel */ +#define H_PERIOD (336 * CLOCKS_PER_PIX) /* HS period */ +#define H_PULSE (2 * CLOCKS_PER_PIX) /* HS pulse width */ +#define H_START (7 * CLOCKS_PER_PIX + CPLD_PIPELINE_DELAY_COR) /* first valid pixel */ + +#define V_LINES (LCD_Y_RES + U_LINE) /* total vertical lines */ +#define V_PULSE (2 * CLOCKS_PER_PIX) /* VS pulse width (1-5 H_PERIODs) */ +#define V_PERIOD (H_PERIOD * V_LINES) /* VS period */ + +#define ACTIVE_VIDEO_MEM_OFFSET ((U_LINE / 2) * LCD_X_RES * (LCD_BPP / 8)) + +#define BFIN_LCD_NBR_PALETTE_ENTRIES 256 + +#define PPI_TX_MODE 0x2 +#define PPI_XFER_TYPE_11 0xC +#define PPI_PORT_CFG_01 0x10 +#define PPI_POLS_1 0x8000 + +#if (CLOCKS_PER_PIX > 1) +#define PPI_PMODE (DLEN_8 | PACK_EN) +#else +#define PPI_PMODE (DLEN_16) +#endif + +#define LQ035_INDEX 0x74 +#define LQ035_DATA 0x76 + +#define LQ035_DRIVER_OUTPUT_CTL 0x1 +#define LQ035_SHUT_CTL 0x11 + +#define LQ035_DRIVER_OUTPUT_MASK (LQ035_LR | LQ035_TB | LQ035_BGR | LQ035_REV) +#define LQ035_DRIVER_OUTPUT_DEFAULT (0x2AEF & ~LQ035_DRIVER_OUTPUT_MASK) + +#define LQ035_SHUT (1 << 0) /* Shutdown */ +#define LQ035_ON (0 << 0) /* Shutdown */ + +struct bfin_lq035q1fb_info { + struct fb_info *fb; + struct device *dev; + struct spi_driver spidrv; + struct bfin_lq035q1fb_disp_info *disp_info; + unsigned char *fb_buffer; /* RGB Buffer */ + dma_addr_t dma_handle; + int lq035_open_cnt; + int irq; + spinlock_t lock; /* lock */ + u32 pseudo_pal[16]; +}; + +static int nocursor; +module_param(nocursor, int, 0644); +MODULE_PARM_DESC(nocursor, "cursor enable/disable"); + +struct spi_control { + unsigned short mode; +}; + +static int lq035q1_control(struct spi_device *spi, unsigned char reg, unsigned short value) +{ + int ret; + u8 regs[3] = { LQ035_INDEX, 0, 0 }; + u8 dat[3] = { LQ035_DATA, 0, 0 }; + + if (!spi) + return -ENODEV; + + regs[2] = reg; + dat[1] = value >> 8; + dat[2] = value & 0xFF; + + ret = spi_write(spi, regs, ARRAY_SIZE(regs)); + ret |= spi_write(spi, dat, ARRAY_SIZE(dat)); + return ret; +} + +static int __devinit lq035q1_spidev_probe(struct spi_device *spi) +{ + int ret; + struct spi_control *ctl; + struct bfin_lq035q1fb_info *info = container_of(spi->dev.driver, + struct bfin_lq035q1fb_info, + spidrv.driver); + + ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); + + if (!ctl) + return -ENOMEM; + + ctl->mode = (info->disp_info->mode & + LQ035_DRIVER_OUTPUT_MASK) | LQ035_DRIVER_OUTPUT_DEFAULT; + + ret = lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON); + ret |= lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode); + if (ret) + return ret; + + spi_set_drvdata(spi, ctl); + + return 0; +} + +static int lq035q1_spidev_remove(struct spi_device *spi) +{ + return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); +} + +#ifdef CONFIG_PM +static int lq035q1_spidev_suspend(struct spi_device *spi, pm_message_t state) +{ + return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); +} + +static int lq035q1_spidev_resume(struct spi_device *spi) +{ + int ret; + struct spi_control *ctl = spi_get_drvdata(spi); + + ret = lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode); + if (ret) + return ret; + + return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON); +} +#else +# define lq035q1_spidev_suspend NULL +# define lq035q1_spidev_resume NULL +#endif + +/* Power down all displays on reboot, poweroff or halt */ +static void lq035q1_spidev_shutdown(struct spi_device *spi) +{ + lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); +} + +static int lq035q1_backlight(struct bfin_lq035q1fb_info *info, unsigned arg) +{ + if (info->disp_info->use_bl) + gpio_set_value(info->disp_info->gpio_bl, arg); + + return 0; +} + +static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info *fbi) +{ + bfin_write_PPI_DELAY(H_START); + bfin_write_PPI_COUNT(H_ACTPIX - 1); + bfin_write_PPI_FRAME(V_LINES); + + bfin_write_PPI_CONTROL(PPI_TX_MODE | /* output mode , PORT_DIR */ + PPI_XFER_TYPE_11 | /* sync mode XFR_TYPE */ + PPI_PORT_CFG_01 | /* two frame sync PORT_CFG */ + PPI_PMODE | /* 8/16 bit data length / PACK_EN? */ + PPI_POLS_1); /* faling edge syncs POLS */ +} + +static inline void bfin_lq035q1_disable_ppi(void) +{ + bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN); +} + +static inline void bfin_lq035q1_enable_ppi(void) +{ + bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN); +} + +static void bfin_lq035q1_start_timers(void) +{ + enable_gptimers(TIMER_VSYNCbit | TIMER_HSYNCbit); +} + +static void bfin_lq035q1_stop_timers(void) +{ + disable_gptimers(TIMER_HSYNCbit | TIMER_VSYNCbit); + + set_gptimer_status(0, TIMER_HSYNC_STATUS_TRUN | TIMER_VSYNC_STATUS_TRUN | + TIMER_HSYNC_STATUS_TIMIL | TIMER_VSYNC_STATUS_TIMIL | + TIMER_HSYNC_STATUS_TOVF | TIMER_VSYNC_STATUS_TOVF); + +} + +static void bfin_lq035q1_init_timers(void) +{ + + bfin_lq035q1_stop_timers(); + + set_gptimer_period(TIMER_HSYNC_id, H_PERIOD); + set_gptimer_pwidth(TIMER_HSYNC_id, H_PULSE); + set_gptimer_config(TIMER_HSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | + TIMER_TIN_SEL | TIMER_CLK_SEL| + TIMER_EMU_RUN); + + set_gptimer_period(TIMER_VSYNC_id, V_PERIOD); + set_gptimer_pwidth(TIMER_VSYNC_id, V_PULSE); + set_gptimer_config(TIMER_VSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | + TIMER_TIN_SEL | TIMER_CLK_SEL | + TIMER_EMU_RUN); + +} + +static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info *fbi) +{ + + set_dma_config(CH_PPI, + set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO, + INTR_DISABLE, DIMENSION_2D, + DATA_SIZE_16, + DMA_NOSYNC_KEEP_DMA_BUF)); + set_dma_x_count(CH_PPI, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE); + set_dma_x_modify(CH_PPI, DMA_BUS_SIZE / 8); + set_dma_y_count(CH_PPI, V_LINES); + + set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8); + set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer); + +} + +#if (CLOCKS_PER_PIX == 1) +static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, + P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, + P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, + P_PPI0_D6, P_PPI0_D7, P_PPI0_D8, + P_PPI0_D9, P_PPI0_D10, P_PPI0_D11, + P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, + P_PPI0_D15, 0}; +#else +static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, + P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, + P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, + P_PPI0_D6, P_PPI0_D7, 0}; +#endif + +static inline void bfin_lq035q1_free_ports(void) +{ + peripheral_free_list(ppi0_req_16); + if (ANOMALY_05000400) + gpio_free(P_IDENT(P_PPI0_FS3)); +} + +static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev) +{ + /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode: + * Drive PPI_FS3 Low + */ + if (ANOMALY_05000400) { + int ret = gpio_request(P_IDENT(P_PPI0_FS3), "PPI_FS3"); + if (ret) + return ret; + gpio_direction_output(P_IDENT(P_PPI0_FS3), 0); + } + + if (peripheral_request_list(ppi0_req_16, DRIVER_NAME)) { + dev_err(&pdev->dev, "requesting peripherals failed\n"); + return -EFAULT; + } + + return 0; +} + +static int bfin_lq035q1_fb_open(struct fb_info *info, int user) +{ + struct bfin_lq035q1fb_info *fbi = info->par; + + spin_lock(&fbi->lock); + fbi->lq035_open_cnt++; + + if (fbi->lq035_open_cnt <= 1) { + + bfin_lq035q1_disable_ppi(); + SSYNC(); + + bfin_lq035q1_config_dma(fbi); + bfin_lq035q1_config_ppi(fbi); + bfin_lq035q1_init_timers(); + + /* start dma */ + enable_dma(CH_PPI); + bfin_lq035q1_enable_ppi(); + bfin_lq035q1_start_timers(); + lq035q1_backlight(fbi, 1); + } + + spin_unlock(&fbi->lock); + + return 0; +} + +static int bfin_lq035q1_fb_release(struct fb_info *info, int user) +{ + struct bfin_lq035q1fb_info *fbi = info->par; + + spin_lock(&fbi->lock); + + fbi->lq035_open_cnt--; + + if (fbi->lq035_open_cnt <= 0) { + lq035q1_backlight(fbi, 0); + bfin_lq035q1_disable_ppi(); + SSYNC(); + disable_dma(CH_PPI); + bfin_lq035q1_stop_timers(); + } + + spin_unlock(&fbi->lock); + + return 0; +} + +static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + switch (var->bits_per_pixel) { +#if (LCD_BPP == 24) + case 24:/* TRUECOLOUR, 16m */ +#else + case 16:/* DIRECTCOLOUR, 64k */ +#endif + var->red.offset = info->var.red.offset; + var->green.offset = info->var.green.offset; + var->blue.offset = info->var.blue.offset; + var->red.length = info->var.red.length; + var->green.length = info->var.green.length; + var->blue.length = info->var.blue.length; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + break; + default: + pr_debug("%s: depth not supported: %u BPP\n", __func__, + var->bits_per_pixel); + return -EINVAL; + } + + if (info->var.xres != var->xres || info->var.yres != var->yres || + info->var.xres_virtual != var->xres_virtual || + info->var.yres_virtual != var->yres_virtual) { + pr_debug("%s: Resolution not supported: X%u x Y%u \n", + __func__, var->xres, var->yres); + return -EINVAL; + } + + /* + * Memory limit + */ + + if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) { + pr_debug("%s: Memory Limit requested yres_virtual = %u\n", + __func__, var->yres_virtual); + return -ENOMEM; + } + + + return 0; +} + +int bfin_lq035q1_fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + if (nocursor) + return 0; + else + return -EINVAL; /* just to force soft_cursor() call */ +} + +static int bfin_lq035q1_fb_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, + struct fb_info *info) +{ + if (regno >= BFIN_LCD_NBR_PALETTE_ENTRIES) + return -EINVAL; + + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + + u32 value; + /* Place color in the pseudopalette */ + if (regno > 16) + return -EINVAL; + + red >>= (16 - info->var.red.length); + green >>= (16 - info->var.green.length); + blue >>= (16 - info->var.blue.length); + + value = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + value &= 0xFFFFFF; + + ((u32 *) (info->pseudo_palette))[regno] = value; + + } + + return 0; +} + +static struct fb_ops bfin_lq035q1_fb_ops = { + .owner = THIS_MODULE, + .fb_open = bfin_lq035q1_fb_open, + .fb_release = bfin_lq035q1_fb_release, + .fb_check_var = bfin_lq035q1_fb_check_var, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = bfin_lq035q1_fb_cursor, + .fb_setcolreg = bfin_lq035q1_fb_setcolreg, +}; + +static irqreturn_t bfin_lq035q1_irq_error(int irq, void *dev_id) +{ + /*struct bfin_lq035q1fb_info *info = (struct bfin_lq035q1fb_info *)dev_id;*/ + + u16 status = bfin_read_PPI_STATUS(); + bfin_write_PPI_STATUS(-1); + + if (status) { + bfin_lq035q1_disable_ppi(); + disable_dma(CH_PPI); + + /* start dma */ + enable_dma(CH_PPI); + bfin_lq035q1_enable_ppi(); + bfin_write_PPI_STATUS(-1); + } + + return IRQ_HANDLED; +} + +static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) +{ + struct bfin_lq035q1fb_info *info; + struct fb_info *fbinfo; + int ret; + + ret = request_dma(CH_PPI, DRIVER_NAME"_CH_PPI"); + if (ret < 0) { + dev_err(&pdev->dev, "PPI DMA unavailable\n"); + goto out1; + } + + fbinfo = framebuffer_alloc(sizeof(*info), &pdev->dev); + if (!fbinfo) { + ret = -ENOMEM; + goto out2; + } + + info = fbinfo->par; + info->fb = fbinfo; + info->dev = &pdev->dev; + + info->disp_info = pdev->dev.platform_data; + + platform_set_drvdata(pdev, fbinfo); + + strcpy(fbinfo->fix.id, DRIVER_NAME); + + fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; + fbinfo->fix.type_aux = 0; + fbinfo->fix.xpanstep = 0; + fbinfo->fix.ypanstep = 0; + fbinfo->fix.ywrapstep = 0; + fbinfo->fix.accel = FB_ACCEL_NONE; + fbinfo->fix.visual = FB_VISUAL_TRUECOLOR; + + fbinfo->var.nonstd = 0; + fbinfo->var.activate = FB_ACTIVATE_NOW; + fbinfo->var.height = -1; + fbinfo->var.width = -1; + fbinfo->var.accel_flags = 0; + fbinfo->var.vmode = FB_VMODE_NONINTERLACED; + + fbinfo->var.xres = LCD_X_RES; + fbinfo->var.xres_virtual = LCD_X_RES; + fbinfo->var.yres = LCD_Y_RES; + fbinfo->var.yres_virtual = LCD_Y_RES; + fbinfo->var.bits_per_pixel = LCD_BPP; + + if (info->disp_info->mode & LQ035_BGR) { +#if (LCD_BPP == 24) + fbinfo->var.red.offset = 0; + fbinfo->var.green.offset = 8; + fbinfo->var.blue.offset = 16; +#else + fbinfo->var.red.offset = 0; + fbinfo->var.green.offset = 5; + fbinfo->var.blue.offset = 11; +#endif + } else { +#if (LCD_BPP == 24) + fbinfo->var.red.offset = 16; + fbinfo->var.green.offset = 8; + fbinfo->var.blue.offset = 0; +#else + fbinfo->var.red.offset = 11; + fbinfo->var.green.offset = 5; + fbinfo->var.blue.offset = 0; +#endif + } + + fbinfo->var.transp.offset = 0; + +#if (LCD_BPP == 24) + fbinfo->var.red.length = 8; + fbinfo->var.green.length = 8; + fbinfo->var.blue.length = 8; +#else + fbinfo->var.red.length = 5; + fbinfo->var.green.length = 6; + fbinfo->var.blue.length = 5; +#endif + + fbinfo->var.transp.length = 0; + + fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * LCD_BPP / 8 + + ACTIVE_VIDEO_MEM_OFFSET; + + fbinfo->fix.line_length = fbinfo->var.xres_virtual * + fbinfo->var.bits_per_pixel / 8; + + + fbinfo->fbops = &bfin_lq035q1_fb_ops; + fbinfo->flags = FBINFO_FLAG_DEFAULT; + + info->fb_buffer = + dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle, + GFP_KERNEL); + + if (NULL == info->fb_buffer) { + dev_err(&pdev->dev, "couldn't allocate dma buffer\n"); + ret = -ENOMEM; + goto out3; + } + + fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; + fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; + + fbinfo->fbops = &bfin_lq035q1_fb_ops; + + fbinfo->pseudo_palette = &info->pseudo_pal; + + ret = fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0); + if (ret < 0) { + dev_err(&pdev->dev, "failed to allocate colormap (%d entries)\n", + BFIN_LCD_NBR_PALETTE_ENTRIES); + goto out4; + } + + ret = bfin_lq035q1_request_ports(pdev); + if (ret) { + dev_err(&pdev->dev, "couldn't request gpio port\n"); + goto out6; + } + + info->irq = platform_get_irq(pdev, 0); + if (info->irq < 0) { + ret = -EINVAL; + goto out7; + } + + ret = request_irq(info->irq, bfin_lq035q1_irq_error, IRQF_DISABLED, + DRIVER_NAME" PPI ERROR", info); + if (ret < 0) { + dev_err(&pdev->dev, "unable to request PPI ERROR IRQ\n"); + goto out7; + } + + info->spidrv.driver.name = DRIVER_NAME"-spi"; + info->spidrv.probe = lq035q1_spidev_probe; + info->spidrv.remove = __devexit_p(lq035q1_spidev_remove); + info->spidrv.shutdown = lq035q1_spidev_shutdown; + info->spidrv.suspend = lq035q1_spidev_suspend; + info->spidrv.resume = lq035q1_spidev_resume; + + ret = spi_register_driver(&info->spidrv); + if (ret < 0) { + dev_err(&pdev->dev, "couldn't register SPI Interface\n"); + goto out8; + } + + if (info->disp_info->use_bl) { + ret = gpio_request(info->disp_info->gpio_bl, "LQ035 Backlight"); + + if (ret) { + dev_err(&pdev->dev, "failed to request GPIO %d\n", + info->disp_info->gpio_bl); + goto out9; + } + gpio_direction_output(info->disp_info->gpio_bl, 0); + } + + ret = register_framebuffer(fbinfo); + if (ret < 0) { + dev_err(&pdev->dev, "unable to register framebuffer\n"); + goto out10; + } + + dev_info(&pdev->dev, "%dx%d %d-bit RGB FrameBuffer initialized\n", + LCD_X_RES, LCD_Y_RES, LCD_BPP); + + return 0; + + out10: + if (info->disp_info->use_bl) + gpio_free(info->disp_info->gpio_bl); + out9: + spi_unregister_driver(&info->spidrv); + out8: + free_irq(info->irq, info); + out7: + bfin_lq035q1_free_ports(); + out6: + fb_dealloc_cmap(&fbinfo->cmap); + out4: + dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, + info->dma_handle); + out3: + framebuffer_release(fbinfo); + out2: + free_dma(CH_PPI); + out1: + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int __devexit bfin_lq035q1_remove(struct platform_device *pdev) +{ + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_lq035q1fb_info *info = fbinfo->par; + + if (info->disp_info->use_bl) + gpio_free(info->disp_info->gpio_bl); + + spi_unregister_driver(&info->spidrv); + + unregister_framebuffer(fbinfo); + + free_dma(CH_PPI); + free_irq(info->irq, info); + + if (info->fb_buffer != NULL) + dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, + info->dma_handle); + + fb_dealloc_cmap(&fbinfo->cmap); + + bfin_lq035q1_free_ports(); + + platform_set_drvdata(pdev, NULL); + framebuffer_release(fbinfo); + + dev_info(&pdev->dev, "unregistered LCD driver\n"); + + return 0; +} + +#ifdef CONFIG_PM +static int bfin_lq035q1_suspend(struct device *dev) +{ + struct fb_info *fbinfo = dev_get_drvdata(dev); + struct bfin_lq035q1fb_info *info = fbinfo->par; + + if (info->lq035_open_cnt) { + lq035q1_backlight(info, 0); + bfin_lq035q1_disable_ppi(); + SSYNC(); + disable_dma(CH_PPI); + bfin_lq035q1_stop_timers(); + bfin_write_PPI_STATUS(-1); + } + + return 0; +} + +static int bfin_lq035q1_resume(struct device *dev) +{ + struct fb_info *fbinfo = dev_get_drvdata(dev); + struct bfin_lq035q1fb_info *info = fbinfo->par; + + if (info->lq035_open_cnt) { + bfin_lq035q1_disable_ppi(); + SSYNC(); + + bfin_lq035q1_config_dma(info); + bfin_lq035q1_config_ppi(info); + bfin_lq035q1_init_timers(); + + /* start dma */ + enable_dma(CH_PPI); + bfin_lq035q1_enable_ppi(); + bfin_lq035q1_start_timers(); + lq035q1_backlight(info, 1); + } + + return 0; +} + +static struct dev_pm_ops bfin_lq035q1_dev_pm_ops = { + .suspend = bfin_lq035q1_suspend, + .resume = bfin_lq035q1_resume, +}; +#endif + +static struct platform_driver bfin_lq035q1_driver = { + .probe = bfin_lq035q1_probe, + .remove = __devexit_p(bfin_lq035q1_remove), + .driver = { + .name = DRIVER_NAME, +#ifdef CONFIG_PM + .pm = &bfin_lq035q1_dev_pm_ops, +#endif + }, +}; + +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_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 5cc36cfbf07..2549c53b26a 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c @@ -487,8 +487,8 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) fbinfo->var.nonstd = 0; fbinfo->var.activate = FB_ACTIVATE_NOW; - fbinfo->var.height = -1; - fbinfo->var.width = -1; + fbinfo->var.height = 53; + fbinfo->var.width = 70; fbinfo->var.accel_flags = 0; fbinfo->var.vmode = FB_VMODE_NONINTERLACED; @@ -634,17 +634,35 @@ static int __devexit bfin_t350mcqb_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t state) { - bfin_t350mcqb_disable_ppi(); - disable_dma(CH_PPI); - bfin_write_PPI_STATUS(0xFFFF); + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_t350mcqbfb_info *fbi = fbinfo->par; + + if (fbi->lq043_open_cnt) { + bfin_t350mcqb_disable_ppi(); + disable_dma(CH_PPI); + bfin_t350mcqb_stop_timers(); + bfin_write_PPI_STATUS(-1); + } + return 0; } static int bfin_t350mcqb_resume(struct platform_device *pdev) { - enable_dma(CH_PPI); - bfin_t350mcqb_enable_ppi(); + struct fb_info *fbinfo = platform_get_drvdata(pdev); + struct bfin_t350mcqbfb_info *fbi = fbinfo->par; + + if (fbi->lq043_open_cnt) { + bfin_t350mcqb_config_dma(fbi); + bfin_t350mcqb_config_ppi(fbi); + bfin_t350mcqb_init_timers(); + + /* start dma */ + enable_dma(CH_PPI); + bfin_t350mcqb_enable_ppi(); + bfin_t350mcqb_start_timers(); + } return 0; } diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c index 16f5db471ab..99b354b8e25 100644 --- a/drivers/video/clps711xfb.c +++ b/drivers/video/clps711xfb.c @@ -19,8 +19,10 @@ * * Framebuffer driver for the CLPS7111 and EP7212 processors. */ +#include <linux/mm.h> #include <linux/module.h> #include <linux/kernel.h> +#include <linux/seq_file.h> #include <linux/slab.h> #include <linux/fb.h> #include <linux/init.h> @@ -38,14 +40,6 @@ struct fb_info *cfb; #define CMAP_MAX_SIZE 16 -/* The /proc entry for the backlight. */ -static struct proc_dir_entry *clps7111fb_backlight_proc_entry = NULL; - -static int clps7111fb_proc_backlight_read(char *page, char **start, off_t off, - int count, int *eof, void *data); -static int clps7111fb_proc_backlight_write(struct file *file, - const char *buffer, unsigned long count, void *data); - /* * LCD AC Prescale. This comes from the LCD panel manufacturers specifications. * This determines how many clocks + 1 of CL1 before the M signal toggles. @@ -221,26 +215,23 @@ static struct fb_ops clps7111fb_ops = { .fb_imageblit = cfb_imageblit, }; -static int -clps7111fb_proc_backlight_read(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int backlight_proc_show(struct seq_file *m, void *v) { - /* We need at least two characters, one for the digit, and one for - * the terminating NULL. */ - if (count < 2) - return -EINVAL; - if (machine_is_edb7211()) { - return sprintf(page, "%d\n", + seq_printf(m, "%d\n", (clps_readb(PDDR) & EDB_PD3_LCDBL) ? 1 : 0); } return 0; } -static int -clps7111fb_proc_backlight_write(struct file *file, const char *buffer, - unsigned long count, void *data) +static int backlight_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, backlight_proc_show, NULL); +} + +static ssize_t backlight_proc_write(struct file *file, const char *buffer, + size_t count, loff_t *pos) { unsigned char char_value; int value; @@ -271,6 +262,15 @@ clps7111fb_proc_backlight_write(struct file *file, const char *buffer, return count; } +static const struct file_operations backlight_proc_fops = { + .owner = THIS_MODULE, + .open = backlight_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = backlight_proc_write, +}; + static void __init clps711x_guess_lcd_params(struct fb_info *info) { unsigned int lcdcon, syscon, size; @@ -379,19 +379,11 @@ int __init clps711xfb_init(void) fb_alloc_cmap(&cfb->cmap, CMAP_MAX_SIZE, 0); - /* Register the /proc entries. */ - clps7111fb_backlight_proc_entry = create_proc_entry("backlight", 0444, - NULL); - if (clps7111fb_backlight_proc_entry == NULL) { + if (!proc_create("backlight", 0444, NULL, &backlight_proc_fops)) { printk("Couldn't create the /proc entry for the backlight.\n"); return -EINVAL; } - clps7111fb_backlight_proc_entry->read_proc = - &clps7111fb_proc_backlight_read; - clps7111fb_backlight_proc_entry->write_proc = - &clps7111fb_proc_backlight_write; - /* * Power up the LCD */ diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index da7c01b39be..3a561df2e8a 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c @@ -1573,15 +1573,15 @@ cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) if (err) return err; - err = pci_request_regions(dev, name); - if (err) - return err; - err = -ENOMEM; cfb = cyberpro_alloc_fb_info(id->driver_data, name); if (!cfb) goto failed_release; + err = pci_request_regions(dev, cfb->fb.fix.id); + if (err) + goto failed_regions; + cfb->dev = dev; cfb->region = pci_ioremap_bar(dev, 0); if (!cfb->region) @@ -1633,10 +1633,10 @@ cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) failed: iounmap(cfb->region); failed_ioremap: + pci_release_regions(dev); +failed_regions: cyberpro_free_fb_info(cfb); failed_release: - pci_release_regions(dev); - return err; } diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index ea1fd3f4751..369a5b3ac64 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -28,6 +28,8 @@ #include <linux/uaccess.h> #include <linux/interrupt.h> #include <linux/clk.h> +#include <linux/cpufreq.h> +#include <linux/console.h> #include <video/da8xx-fb.h> #define DRIVER_NAME "da8xx_lcdc" @@ -113,6 +115,12 @@ struct da8xx_fb_par { unsigned short pseudo_palette[16]; unsigned int databuf_sz; unsigned int palette_sz; + unsigned int pxl_clk; + int blank; +#ifdef CONFIG_CPU_FREQ + struct notifier_block freq_transition; +#endif + void (*panel_power_ctrl)(int); }; /* Variable Screen Information */ @@ -155,7 +163,7 @@ struct da8xx_panel { int vfp; /* Vertical front porch */ int vbp; /* Vertical back porch */ int vsw; /* Vertical Sync Pulse Width */ - int pxl_clk; /* Pixel clock */ + unsigned int pxl_clk; /* Pixel clock */ unsigned char invert_pxl_clk; /* Invert Pixel clock */ }; @@ -171,7 +179,7 @@ static struct da8xx_panel known_lcd_panels[] = { .vfp = 2, .vbp = 2, .vsw = 0, - .pxl_clk = 0x10, + .pxl_clk = 4608000, .invert_pxl_clk = 1, }, /* Sharp LK043T1DG01 */ @@ -185,13 +193,23 @@ static struct da8xx_panel known_lcd_panels[] = { .vfp = 2, .vbp = 2, .vsw = 10, - .pxl_clk = 0x12, + .pxl_clk = 7833600, .invert_pxl_clk = 0, }, }; +/* Enable the Raster Engine of the LCD Controller */ +static inline void lcd_enable_raster(void) +{ + u32 reg; + + reg = lcdc_read(LCD_RASTER_CTRL_REG); + if (!(reg & LCD_RASTER_ENABLE)) + lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); +} + /* Disable the Raster Engine of the LCD Controller */ -static void lcd_disable_raster(struct da8xx_fb_par *par) +static inline void lcd_disable_raster(void) { u32 reg; @@ -443,14 +461,25 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, static void lcd_reset(struct da8xx_fb_par *par) { /* Disable the Raster if previously Enabled */ - if (lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE) - lcd_disable_raster(par); + lcd_disable_raster(); /* DMA has to be disabled */ lcdc_write(0, LCD_DMA_CTRL_REG); lcdc_write(0, LCD_RASTER_CTRL_REG); } +static void lcd_calc_clk_divider(struct da8xx_fb_par *par) +{ + unsigned int lcd_clk, div; + + lcd_clk = clk_get_rate(par->lcdc_clk); + div = lcd_clk / par->pxl_clk; + + /* Configure the LCD clock divisor. */ + lcdc_write(LCD_CLK_DIVISOR(div) | + (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG); +} + static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, struct da8xx_panel *panel) { @@ -459,9 +488,8 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, lcd_reset(par); - /* Configure the LCD clock divisor. */ - lcdc_write(LCD_CLK_DIVISOR(panel->pxl_clk) | - (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG); + /* Calculate the divider */ + lcd_calc_clk_divider(par); if (panel->invert_pxl_clk) lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) | @@ -513,13 +541,11 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, static irqreturn_t lcdc_irq_handler(int irq, void *arg) { u32 stat = lcdc_read(LCD_STAT_REG); - u32 reg; if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { - reg = lcdc_read(LCD_RASTER_CTRL_REG); - lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); + lcd_disable_raster(); lcdc_write(stat, LCD_STAT_REG); - lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); + lcd_enable_raster(); } else lcdc_write(stat, LCD_STAT_REG); @@ -574,6 +600,38 @@ static int fb_check_var(struct fb_var_screeninfo *var, return err; } +#ifdef CONFIG_CPU_FREQ +static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct da8xx_fb_par *par; + + par = container_of(nb, struct da8xx_fb_par, freq_transition); + if (val == CPUFREQ_PRECHANGE) { + lcd_disable_raster(); + } else if (val == CPUFREQ_POSTCHANGE) { + lcd_calc_clk_divider(par); + lcd_enable_raster(); + } + + return 0; +} + +static inline int lcd_da8xx_cpufreq_register(struct da8xx_fb_par *par) +{ + par->freq_transition.notifier_call = lcd_da8xx_cpufreq_transition; + + return cpufreq_register_notifier(&par->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +} + +static inline void lcd_da8xx_cpufreq_deregister(struct da8xx_fb_par *par) +{ + cpufreq_unregister_notifier(&par->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +} +#endif + static int __devexit fb_remove(struct platform_device *dev) { struct fb_info *info = dev_get_drvdata(&dev->dev); @@ -581,8 +639,13 @@ static int __devexit fb_remove(struct platform_device *dev) if (info) { struct da8xx_fb_par *par = info->par; - if (lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE) - lcd_disable_raster(par); +#ifdef CONFIG_CPU_FREQ + lcd_da8xx_cpufreq_deregister(par); +#endif + if (par->panel_power_ctrl) + par->panel_power_ctrl(0); + + lcd_disable_raster(); lcdc_write(0, LCD_RASTER_CTRL_REG); /* disable DMA */ @@ -639,6 +702,35 @@ static int fb_ioctl(struct fb_info *info, unsigned int cmd, return 0; } +static int cfb_blank(int blank, struct fb_info *info) +{ + struct da8xx_fb_par *par = info->par; + int ret = 0; + + if (par->blank == blank) + return 0; + + par->blank = blank; + switch (blank) { + case FB_BLANK_UNBLANK: + if (par->panel_power_ctrl) + par->panel_power_ctrl(1); + + lcd_enable_raster(); + break; + case FB_BLANK_POWERDOWN: + if (par->panel_power_ctrl) + par->panel_power_ctrl(0); + + lcd_disable_raster(); + break; + default: + ret = -EINVAL; + } + + return ret; +} + static struct fb_ops da8xx_fb_ops = { .owner = THIS_MODULE, .fb_check_var = fb_check_var, @@ -647,6 +739,7 @@ static struct fb_ops da8xx_fb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, + .fb_blank = cfb_blank, }; static int __init fb_probe(struct platform_device *device) @@ -721,6 +814,12 @@ static int __init fb_probe(struct platform_device *device) } par = da8xx_fb_info->par; + par->lcdc_clk = fb_clk; + par->pxl_clk = lcdc_info->pxl_clk; + if (fb_pdata->panel_power_ctrl) { + par->panel_power_ctrl = fb_pdata->panel_power_ctrl; + par->panel_power_ctrl(1); + } if (lcd_init(par, lcd_cfg, lcdc_info) < 0) { dev_err(&device->dev, "lcd_init failed\n"); @@ -754,8 +853,6 @@ static int __init fb_probe(struct platform_device *device) da8xx_fb_fix.smem_len = par->databuf_sz - par->palette_sz; da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8; - par->lcdc_clk = fb_clk; - par->irq = platform_get_irq(device, 0); if (par->irq < 0) { ret = -ENOENT; @@ -814,12 +911,24 @@ static int __init fb_probe(struct platform_device *device) goto err_dealloc_cmap; } +#ifdef CONFIG_CPU_FREQ + ret = lcd_da8xx_cpufreq_register(par); + if (ret) { + dev_err(&device->dev, "failed to register cpufreq\n"); + goto err_cpu_freq; + } +#endif + /* enable raster engine */ - lcdc_write(lcdc_read(LCD_RASTER_CTRL_REG) | - LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); + lcd_enable_raster(); return 0; +#ifdef CONFIG_CPU_FREQ +err_cpu_freq: + unregister_framebuffer(da8xx_fb_info); +#endif + err_dealloc_cmap: fb_dealloc_cmap(&da8xx_fb_info->cmap); @@ -852,11 +961,35 @@ err_request_mem: #ifdef CONFIG_PM static int fb_suspend(struct platform_device *dev, pm_message_t state) { - return -EBUSY; + struct fb_info *info = platform_get_drvdata(dev); + struct da8xx_fb_par *par = info->par; + + acquire_console_sem(); + if (par->panel_power_ctrl) + par->panel_power_ctrl(0); + + fb_set_suspend(info, 1); + lcd_disable_raster(); + clk_disable(par->lcdc_clk); + release_console_sem(); + + return 0; } static int fb_resume(struct platform_device *dev) { - return -EBUSY; + struct fb_info *info = platform_get_drvdata(dev); + struct da8xx_fb_par *par = info->par; + + acquire_console_sem(); + if (par->panel_power_ctrl) + par->panel_power_ctrl(1); + + clk_enable(par->lcdc_clk); + lcd_enable_raster(); + fb_set_suspend(info, 0); + release_console_sem(); + + return 0; } #else #define fb_suspend NULL diff --git a/drivers/video/display/display-sysfs.c b/drivers/video/display/display-sysfs.c index 4830b1bf51e..80abbf323b9 100644 --- a/drivers/video/display/display-sysfs.c +++ b/drivers/video/display/display-sysfs.c @@ -67,7 +67,7 @@ static ssize_t display_store_contrast(struct device *dev, contrast = simple_strtoul(buf, &endp, 0); size = endp - buf; - if (*endp && isspace(*endp)) + if (isspace(*endp)) size++; if (size != count) diff --git a/drivers/video/ep93xx-fb.c b/drivers/video/ep93xx-fb.c index bd9d46f9529..27aab4a0619 100644 --- a/drivers/video/ep93xx-fb.c +++ b/drivers/video/ep93xx-fb.c @@ -358,6 +358,8 @@ static int ep93xxfb_setcolreg(unsigned int regno, unsigned int red, switch (info->fix.visual) { case FB_VISUAL_PSEUDOCOLOR: + if (regno > 255) + return 1; rgb = ((red & 0xff00) << 8) | (green & 0xff00) | ((blue & 0xff00) >> 8); diff --git a/drivers/video/geode/display_gx.c b/drivers/video/geode/display_gx.c index e759895bf3d..f0af911a096 100644 --- a/drivers/video/geode/display_gx.c +++ b/drivers/video/geode/display_gx.c @@ -17,7 +17,7 @@ #include <asm/io.h> #include <asm/div64.h> #include <asm/delay.h> -#include <asm/geode.h> +#include <linux/cs5535.h> #include "gxfb.h" @@ -25,7 +25,7 @@ unsigned int gx_frame_buffer_size(void) { unsigned int val; - if (!geode_has_vsa2()) { + if (!cs5535_has_vsa2()) { uint32_t hi, lo; /* The number of pages is (PMAX - PMIN)+1 */ diff --git a/drivers/video/geode/gxfb.h b/drivers/video/geode/gxfb.h index 16a96f8fd8c..d19e9378b0c 100644 --- a/drivers/video/geode/gxfb.h +++ b/drivers/video/geode/gxfb.h @@ -340,7 +340,7 @@ static inline void write_fp(struct gxfb_par *par, int reg, uint32_t val) } -/* MSRs are defined in asm/geode.h; their bitfields are here */ +/* MSRs are defined in linux/cs5535.h; their bitfields are here */ #define MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 (1 << 3) #define MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 (1 << 2) diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c index 2552cac39e1..b3e639d1e12 100644 --- a/drivers/video/geode/gxfb_core.c +++ b/drivers/video/geode/gxfb_core.c @@ -32,7 +32,7 @@ #include <linux/suspend.h> #include <linux/init.h> #include <linux/pci.h> -#include <asm/geode.h> +#include <linux/cs5535.h> #include "gxfb.h" diff --git a/drivers/video/geode/lxfb.h b/drivers/video/geode/lxfb.h index 6a51448fd3f..cc781c00f75 100644 --- a/drivers/video/geode/lxfb.h +++ b/drivers/video/geode/lxfb.h @@ -1,3 +1,13 @@ +/* Geode LX framebuffer driver + * + * Copyright (C) 2006-2007, Advanced Micro Devices,Inc. + * Copyright (c) 2008 Andres Salomon <dilinger@debian.org> + * + * 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 of the License, or (at your + * option) any later version. + */ #ifndef _LXFB_H_ #define _LXFB_H_ @@ -409,7 +419,7 @@ static inline void write_fp(struct lxfb_par *par, int reg, uint32_t val) } -/* MSRs are defined in asm/geode.h; their bitfields are here */ +/* MSRs are defined in linux/cs5535.h; their bitfields are here */ #define MSR_GLCP_DOTPLL_LOCK (1 << 25) /* r/o */ #define MSR_GLCP_DOTPLL_HALFPIX (1 << 24) diff --git a/drivers/video/geode/lxfb_ops.c b/drivers/video/geode/lxfb_ops.c index b1cd49c9935..0e5d8c7c3eb 100644 --- a/drivers/video/geode/lxfb_ops.c +++ b/drivers/video/geode/lxfb_ops.c @@ -13,7 +13,7 @@ #include <linux/fb.h> #include <linux/uaccess.h> #include <linux/delay.h> -#include <asm/geode.h> +#include <linux/cs5535.h> #include "lxfb.h" @@ -307,7 +307,7 @@ unsigned int lx_framebuffer_size(void) { unsigned int val; - if (!geode_has_vsa2()) { + if (!cs5535_has_vsa2()) { uint32_t hi, lo; /* The number of pages is (PMAX - PMIN)+1 */ diff --git a/drivers/video/geode/suspend_gx.c b/drivers/video/geode/suspend_gx.c index 9aff32ef8bb..1bb043d70c6 100644 --- a/drivers/video/geode/suspend_gx.c +++ b/drivers/video/geode/suspend_gx.c @@ -10,7 +10,7 @@ #include <linux/fb.h> #include <asm/io.h> #include <asm/msr.h> -#include <asm/geode.h> +#include <linux/cs5535.h> #include <asm/delay.h> #include "gxfb.h" diff --git a/drivers/video/geode/video_gx.c b/drivers/video/geode/video_gx.c index b8d52a8360d..6082f653c68 100644 --- a/drivers/video/geode/video_gx.c +++ b/drivers/video/geode/video_gx.c @@ -16,7 +16,7 @@ #include <asm/io.h> #include <asm/delay.h> #include <asm/msr.h> -#include <asm/geode.h> +#include <linux/cs5535.h> #include "gxfb.h" diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c index e7116a6d82d..73c83a8de2d 100644 --- a/drivers/video/hitfb.c +++ b/drivers/video/hitfb.c @@ -456,7 +456,7 @@ static int hitfb_resume(struct device *dev) return 0; } -static struct dev_pm_ops hitfb_dev_pm_ops = { +static const struct dev_pm_ops hitfb_dev_pm_ops = { .suspend = hitfb_suspend, .resume = hitfb_resume, }; diff --git a/drivers/video/i810/i810_dvt.c b/drivers/video/i810/i810_dvt.c index 27fa703a2e0..b4b3670667a 100644 --- a/drivers/video/i810/i810_dvt.c +++ b/drivers/video/i810/i810_dvt.c @@ -212,24 +212,29 @@ inline void round_off_yres(u32 *xres, u32 *yres) *yres = (*xres * 3) >> 2; } -void i810fb_encode_registers(const struct fb_var_screeninfo *var, - struct i810fb_par *par, u32 xres, u32 yres) +static int i810fb_find_best_mode(u32 xres, u32 yres, u32 pixclock) { u32 diff = 0, diff_best = 0xFFFFFFFF, i = 0, i_best = 0; - u8 hfl; + u8 hfl = (u8) ((xres >> 3) - 1); - hfl = (u8) ((xres >> 3) - 1); for (i = 0; i < ARRAY_SIZE(std_modes); i++) { if (std_modes[i].cr01 == hfl) { - if (std_modes[i].pixclock <= par->regs.pixclock) - diff = par->regs.pixclock - - std_modes[i].pixclock; + if (std_modes[i].pixclock <= pixclock) + diff = pixclock - std_modes[i].pixclock; if (diff < diff_best) { i_best = i; diff_best = diff; } } } + return i_best; +} + +void i810fb_encode_registers(const struct fb_var_screeninfo *var, + struct i810fb_par *par, u32 xres, u32 yres) +{ + u32 i_best = i810fb_find_best_mode(xres, yres, par->regs.pixclock); + par->regs = std_modes[i_best]; /* overlay */ @@ -239,36 +244,36 @@ void i810fb_encode_registers(const struct fb_var_screeninfo *var, void i810fb_fill_var_timings(struct fb_var_screeninfo *var) { - struct i810fb_par par; u32 total, xres, yres; + u32 mode, pixclock; xres = var->xres; yres = var->yres; - par.regs.pixclock = 1000000000/var->pixclock; - i810fb_encode_registers(var, &par, xres, yres); + pixclock = 1000000000 / var->pixclock; + mode = i810fb_find_best_mode(xres, yres, pixclock); - total = ((par.regs.cr00 | (par.regs.cr35 & 1) << 8) + 3) << 3; + total = (std_modes[mode].cr00 | (std_modes[mode].cr35 & 1) << 8) + 3; + total <<= 3; - var->pixclock = 1000000000/par.regs.pixclock; - var->right_margin = (par.regs.cr04 << 3) - xres; - var->hsync_len = ((par.regs.cr05 & 0x1F) - - (par.regs.cr04 & 0x1F)) << 3; + var->pixclock = 1000000000 / std_modes[mode].pixclock; + var->right_margin = (std_modes[mode].cr04 << 3) - xres; + var->hsync_len = ((std_modes[mode].cr05 & 0x1F) - + (std_modes[mode].cr04 & 0x1F)) << 3; var->left_margin = (total - (xres + var->right_margin + var->hsync_len)); var->sync = FB_SYNC_ON_GREEN; - if (~(par.regs.msr & (1 << 6))) + if (~(std_modes[mode].msr & (1 << 6))) var->sync |= FB_SYNC_HOR_HIGH_ACT; - if (~(par.regs.msr & (1 << 7))) + if (~(std_modes[mode].msr & (1 << 7))) var->sync |= FB_SYNC_VERT_HIGH_ACT; - - total = ((par.regs.cr06 | (par.regs.cr30 & 0x0F) << 8)) + 2; - var->lower_margin = (par.regs.cr10 | - (par.regs.cr32 & 0x0F) << 8) - yres; - var->vsync_len = (par.regs.cr11 & 0x0F) - (var->lower_margin & 0x0F); - var->upper_margin = total - (yres + var->lower_margin + - var->vsync_len); + total = (std_modes[mode].cr06 | (std_modes[mode].cr30 & 0xF) << 8) + 2; + var->lower_margin = (std_modes[mode].cr10 | + (std_modes[mode].cr32 & 0x0F) << 8) - yres; + var->vsync_len = (std_modes[mode].cr11 & 0x0F) - + (var->lower_margin & 0x0F); + var->upper_margin = total - (yres + var->lower_margin + var->vsync_len); } u32 i810_get_watermark(struct fb_var_screeninfo *var, diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 0cafd642fbc..5ba39999105 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -874,6 +874,9 @@ static int __devinit intelfb_pci_register(struct pci_dev *pdev, if (bailearly == 18) bailout(dinfo); + /* read active pipe */ + dinfo->pipe = intelfbhw_active_pipe(&dinfo->save_state); + /* Cursor initialisation */ if (dinfo->hwcursor) { intelfbhw_cursor_init(dinfo); diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 0689f97c523..81627466804 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -469,6 +469,32 @@ void intelfbhw_do_blank(int blank, struct fb_info *info) } +/* Check which pipe is connected to an active display plane. */ +int intelfbhw_active_pipe(const struct intelfb_hwstate *hw) +{ + int pipe = -1; + + /* keep old default behaviour - prefer PIPE_A */ + if (hw->disp_b_ctrl & DISPPLANE_PLANE_ENABLE) { + pipe = (hw->disp_b_ctrl >> DISPPLANE_SEL_PIPE_SHIFT); + pipe &= PIPE_MASK; + if (unlikely(pipe == PIPE_A)) + return PIPE_A; + } + if (hw->disp_a_ctrl & DISPPLANE_PLANE_ENABLE) { + pipe = (hw->disp_a_ctrl >> DISPPLANE_SEL_PIPE_SHIFT); + pipe &= PIPE_MASK; + if (likely(pipe == PIPE_A)) + return PIPE_A; + } + /* Impossible that no pipe is selected - return PIPE_A */ + WARN_ON(pipe == -1); + if (unlikely(pipe == -1)) + pipe = PIPE_A; + + return pipe; +} + void intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp) @@ -1019,7 +1045,7 @@ int intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, struct fb_var_screeninfo *var) { - int pipe = PIPE_A; + int pipe = intelfbhw_active_pipe(hw); u32 *dpll, *fp0, *fp1; u32 m1, m2, n, p1, p2, clock_target, clock; u32 hsync_start, hsync_end, hblank_start, hblank_end, htotal, hactive; @@ -1033,12 +1059,6 @@ int intelfbhw_mode_to_hw(struct intelfb_info *dinfo, /* Disable VGA */ hw->vgacntrl |= VGA_DISABLE; - /* Check whether pipe A or pipe B is enabled. */ - if (hw->pipe_a_conf & PIPECONF_ENABLE) - pipe = PIPE_A; - else if (hw->pipe_b_conf & PIPECONF_ENABLE) - pipe = PIPE_B; - /* Set which pipe's registers will be set. */ if (pipe == PIPE_B) { dpll = &hw->dpll_b; @@ -1262,7 +1282,6 @@ int intelfbhw_mode_to_hw(struct intelfb_info *dinfo, int intelfbhw_program_mode(struct intelfb_info *dinfo, const struct intelfb_hwstate *hw, int blank) { - int pipe = PIPE_A; u32 tmp; const u32 *dpll, *fp0, *fp1, *pipe_conf; const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss; @@ -1272,7 +1291,7 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo, u32 src_size_reg; u32 count, tmp_val[3]; - /* Assume single pipe, display plane A, analog CRT. */ + /* Assume single pipe */ #if VERBOSE > 0 DBG_MSG("intelfbhw_program_mode\n"); @@ -1283,15 +1302,9 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo, tmp |= VGA_DISABLE; OUTREG(VGACNTRL, tmp); - /* Check whether pipe A or pipe B is enabled. */ - if (hw->pipe_a_conf & PIPECONF_ENABLE) - pipe = PIPE_A; - else if (hw->pipe_b_conf & PIPECONF_ENABLE) - pipe = PIPE_B; - - dinfo->pipe = pipe; + dinfo->pipe = intelfbhw_active_pipe(hw); - if (pipe == PIPE_B) { + if (dinfo->pipe == PIPE_B) { dpll = &hw->dpll_b; fp0 = &hw->fpb0; fp1 = &hw->fpb1; diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h index 0b076bac321..216ca20f259 100644 --- a/drivers/video/intelfb/intelfbhw.h +++ b/drivers/video/intelfb/intelfbhw.h @@ -604,5 +604,6 @@ extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo); extern int intelfbhw_enable_irq(struct intelfb_info *dinfo); extern void intelfbhw_disable_irq(struct intelfb_info *dinfo); extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe); +extern int intelfbhw_active_pipe(const struct intelfb_hwstate *hw); #endif /* _INTELFBHW_H */ diff --git a/drivers/video/matrox/g450_pll.c b/drivers/video/matrox/g450_pll.c index 09f6e045d5b..c15f8a57498 100644 --- a/drivers/video/matrox/g450_pll.c +++ b/drivers/video/matrox/g450_pll.c @@ -368,7 +368,8 @@ static int __g450_setclk(struct matrox_fb_info *minfo, unsigned int fout, M1064_XDVICLKCTRL_C1DVICLKEN | M1064_XDVICLKCTRL_DVILOOPCTL | M1064_XDVICLKCTRL_P1LOOPBWDTCTL; - matroxfb_DAC_out(minfo, M1064_XDVICLKCTRL, tmp); + /* Setting this breaks PC systems so don't do it */ + /* matroxfb_DAC_out(minfo, M1064_XDVICLKCTRL, tmp); */ matroxfb_DAC_out(minfo, M1064_XPWRCTRL, xpwrctrl); diff --git a/drivers/video/maxinefb.c b/drivers/video/maxinefb.c index 5e91c2b30af..7854c7a37dc 100644 --- a/drivers/video/maxinefb.c +++ b/drivers/video/maxinefb.c @@ -92,6 +92,9 @@ static int maxinefb_setcolreg(unsigned regno, unsigned red, unsigned green, /* value to be written into the palette reg. */ unsigned long hw_colorvalue = 0; + if (regno > 255) + return 1; + red >>= 8; /* The cmap fields are 16 bits */ green >>= 8; /* wide, but the harware colormap */ blue >>= 8; /* registers are only 8 bits wide */ diff --git a/drivers/video/mb862xx/Makefile b/drivers/video/mb862xx/Makefile index 07664814bb1..d7777714166 100644 --- a/drivers/video/mb862xx/Makefile +++ b/drivers/video/mb862xx/Makefile @@ -2,4 +2,4 @@ # Makefile for the MB862xx framebuffer driver # -obj-$(CONFIG_FB_MB862XX) := mb862xxfb.o +obj-$(CONFIG_FB_MB862XX) := mb862xxfb.o mb862xxfb_accel.o diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfb.c index a28e3cfbbf7..fabb0c59a21 100644 --- a/drivers/video/mb862xx/mb862xxfb.c +++ b/drivers/video/mb862xx/mb862xxfb.c @@ -214,6 +214,8 @@ static int mb862xxfb_set_par(struct fb_info *fbi) unsigned long reg, sc; dev_dbg(par->dev, "%s\n", __func__); + if (par->type == BT_CORALP) + mb862xxfb_init_accel(fbi, fbi->var.xres); if (par->pre_init) return 0; @@ -453,6 +455,18 @@ static ssize_t mb862xxfb_show_dispregs(struct device *dev, ptr += sprintf(ptr, "%08x = %08x\n", reg, inreg(disp, reg)); + for (reg = 0x400; reg <= 0x410; reg += 4) + ptr += sprintf(ptr, "geo %08x = %08x\n", + reg, inreg(geo, reg)); + + for (reg = 0x400; reg <= 0x410; reg += 4) + ptr += sprintf(ptr, "draw %08x = %08x\n", + reg, inreg(draw, reg)); + + for (reg = 0x440; reg <= 0x450; reg += 4) + ptr += sprintf(ptr, "draw %08x = %08x\n", + reg, inreg(draw, reg)); + return ptr - buf; } diff --git a/drivers/video/mb862xx/mb862xxfb.h b/drivers/video/mb862xx/mb862xxfb.h index c4c8f4dd221..d7e7cb76bbf 100644 --- a/drivers/video/mb862xx/mb862xxfb.h +++ b/drivers/video/mb862xx/mb862xxfb.h @@ -61,6 +61,8 @@ struct mb862xxfb_par { u32 pseudo_palette[16]; }; +extern void mb862xxfb_init_accel(struct fb_info *info, int xres); + #if defined(CONFIG_FB_MB862XX_LIME) && defined(CONFIG_FB_MB862XX_PCI_GDC) #error "Select Lime GDC or CoralP/Carmine support, but not both together" #endif diff --git a/drivers/video/mb862xx/mb862xxfb_accel.c b/drivers/video/mb862xx/mb862xxfb_accel.c new file mode 100644 index 00000000000..049256052b1 --- /dev/null +++ b/drivers/video/mb862xx/mb862xxfb_accel.c @@ -0,0 +1,331 @@ +/* + * drivers/mb862xx/mb862xxfb_accel.c + * + * Fujitsu Carmine/Coral-P(A)/Lime framebuffer driver acceleration support + * + * (C) 2007 Alexander Shishkin <virtuoso@slind.org> + * (C) 2009 Valentin Sitdikov <valentin.sitdikov@siemens.com> + * (C) 2009 Siemens AG + * + * 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/fb.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#if defined(CONFIG_OF) +#include <linux/of_platform.h> +#endif +#include "mb862xxfb.h" +#include "mb862xx_reg.h" +#include "mb862xxfb_accel.h" + +static void mb862xxfb_write_fifo(u32 count, u32 *data, struct fb_info *info) +{ + struct mb862xxfb_par *par = info->par; + static u32 free; + + u32 total = 0; + while (total < count) { + if (free) { + outreg(geo, GDC_GEO_REG_INPUT_FIFO, data[total]); + total++; + free--; + } else { + free = (u32) inreg(draw, GDC_REG_FIFO_COUNT); + } + } +} + +static void mb86290fb_copyarea(struct fb_info *info, + const struct fb_copyarea *area) +{ + __u32 cmd[6]; + + cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP; + /* Set raster operation */ + cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9); + cmd[2] = GDC_TYPE_BLTCOPYP << 24; + + if (area->sx >= area->dx && area->sy >= area->dy) + cmd[2] |= GDC_CMD_BLTCOPY_TOP_LEFT << 16; + else if (area->sx >= area->dx && area->sy <= area->dy) + cmd[2] |= GDC_CMD_BLTCOPY_BOTTOM_LEFT << 16; + else if (area->sx <= area->dx && area->sy >= area->dy) + cmd[2] |= GDC_CMD_BLTCOPY_TOP_RIGHT << 16; + else + cmd[2] |= GDC_CMD_BLTCOPY_BOTTOM_RIGHT << 16; + + cmd[3] = (area->sy << 16) | area->sx; + cmd[4] = (area->dy << 16) | area->dx; + cmd[5] = (area->height << 16) | area->width; + mb862xxfb_write_fifo(6, cmd, info); +} + +/* + * Fill in the cmd array /GDC FIFO commands/ to draw a 1bit image. + * Make sure cmd has enough room! + */ +static void mb86290fb_imageblit1(u32 *cmd, u16 step, u16 dx, u16 dy, + u16 width, u16 height, u32 fgcolor, + u32 bgcolor, const struct fb_image *image, + struct fb_info *info) +{ + int i; + unsigned const char *line; + u16 bytes; + + /* set colors and raster operation regs */ + cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP; + /* Set raster operation */ + cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9); + cmd[2] = + (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_FORE_COLOR << 16); + cmd[3] = fgcolor; + cmd[4] = + (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_BACK_COLOR << 16); + cmd[5] = bgcolor; + + i = 0; + line = image->data; + bytes = (image->width + 7) >> 3; + + /* and the image */ + cmd[6] = (GDC_TYPE_DRAWBITMAPP << 24) | + (GDC_CMD_BITMAP << 16) | (2 + (step * height)); + cmd[7] = (dy << 16) | dx; + cmd[8] = (height << 16) | width; + + while (i < height) { + memcpy(&cmd[9 + i * step], line, step << 2); +#ifdef __LITTLE_ENDIAN + { + int k = 0; + for (k = 0; k < step; k++) + cmd[9 + i * step + k] = + cpu_to_be32(cmd[9 + i * step + k]); + } +#endif + line += bytes; + i++; + } +} + +/* + * Fill in the cmd array /GDC FIFO commands/ to draw a 8bit image. + * Make sure cmd has enough room! + */ +static void mb86290fb_imageblit8(u32 *cmd, u16 step, u16 dx, u16 dy, + u16 width, u16 height, u32 fgcolor, + u32 bgcolor, const struct fb_image *image, + struct fb_info *info) +{ + int i, j; + unsigned const char *line, *ptr; + u16 bytes; + + cmd[0] = (GDC_TYPE_DRAWBITMAPP << 24) | + (GDC_CMD_BLT_DRAW << 16) | (2 + (height * step)); + cmd[1] = (dy << 16) | dx; + cmd[2] = (height << 16) | width; + + i = 0; + line = ptr = image->data; + bytes = image->width; + + while (i < height) { + ptr = line; + for (j = 0; j < step; j++) { + cmd[3 + i * step + j] = + (((u32 *) (info->pseudo_palette))[*ptr]) & 0xffff; + ptr++; + cmd[3 + i * step + j] |= + ((((u32 *) (info-> + pseudo_palette))[*ptr]) & 0xffff) << 16; + ptr++; + } + + line += bytes; + i++; + } +} + +/* + * Fill in the cmd array /GDC FIFO commands/ to draw a 16bit image. + * Make sure cmd has enough room! + */ +static void mb86290fb_imageblit16(u32 *cmd, u16 step, u16 dx, u16 dy, + u16 width, u16 height, u32 fgcolor, + u32 bgcolor, const struct fb_image *image, + struct fb_info *info) +{ + int i; + unsigned const char *line; + u16 bytes; + + i = 0; + line = image->data; + bytes = image->width << 1; + + cmd[0] = (GDC_TYPE_DRAWBITMAPP << 24) | + (GDC_CMD_BLT_DRAW << 16) | (2 + step * height); + cmd[1] = (dy << 16) | dx; + cmd[2] = (height << 16) | width; + + while (i < height) { + memcpy(&cmd[3 + i * step], line, step); + line += bytes; + i++; + } +} + +static void mb86290fb_imageblit(struct fb_info *info, + const struct fb_image *image) +{ + int mdr; + u32 *cmd = NULL; + void (*cmdfn) (u32 *, u16, u16, u16, u16, u16, u32, u32, + const struct fb_image *, struct fb_info *) = NULL; + u32 cmdlen; + u32 fgcolor = 0, bgcolor = 0; + u16 step; + + u16 width = image->width, height = image->height; + u16 dx = image->dx, dy = image->dy; + int x2, y2, vxres, vyres; + + mdr = (GDC_ROP_COPY << 9); + x2 = image->dx + image->width; + y2 = image->dy + image->height; + vxres = info->var.xres_virtual; + vyres = info->var.yres_virtual; + x2 = min(x2, vxres); + y2 = min(y2, vyres); + width = x2 - dx; + height = y2 - dy; + + switch (image->depth) { + case 1: + step = (width + 31) >> 5; + cmdlen = 9 + height * step; + cmdfn = mb86290fb_imageblit1; + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + fgcolor = + ((u32 *) (info->pseudo_palette))[image->fg_color]; + bgcolor = + ((u32 *) (info->pseudo_palette))[image->bg_color]; + } else { + fgcolor = image->fg_color; + bgcolor = image->bg_color; + } + + break; + + case 8: + step = (width + 1) >> 1; + cmdlen = 3 + height * step; + cmdfn = mb86290fb_imageblit8; + break; + + case 16: + step = (width + 1) >> 1; + cmdlen = 3 + height * step; + cmdfn = mb86290fb_imageblit16; + break; + + default: + cfb_imageblit(info, image); + return; + } + + cmd = kmalloc(cmdlen * 4, GFP_DMA); + if (!cmd) + return cfb_imageblit(info, image); + cmdfn(cmd, step, dx, dy, width, height, fgcolor, bgcolor, image, info); + mb862xxfb_write_fifo(cmdlen, cmd, info); + kfree(cmd); +} + +static void mb86290fb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect) +{ + + u32 x2, y2, vxres, vyres, height, width, fg; + u32 cmd[7]; + + vxres = info->var.xres_virtual; + vyres = info->var.yres_virtual; + + if (!rect->width || !rect->height || rect->dx > vxres + || rect->dy > vyres) + return; + + /* We could use hardware clipping but on many cards you get around + * hardware clipping by writing to framebuffer directly. */ + x2 = rect->dx + rect->width; + y2 = rect->dy + rect->height; + x2 = min(x2, vxres); + y2 = min(y2, vyres); + width = x2 - rect->dx; + height = y2 - rect->dy; + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) + fg = ((u32 *) (info->pseudo_palette))[rect->color]; + else + fg = rect->color; + + switch (rect->rop) { + + case ROP_XOR: + /* Set raster operation */ + cmd[1] = (2 << 7) | (GDC_ROP_XOR << 9); + break; + + case ROP_COPY: + /* Set raster operation */ + cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9); + break; + + } + + cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP; + /* cmd[1] set earlier */ + cmd[2] = + (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_FORE_COLOR << 16); + cmd[3] = fg; + cmd[4] = (GDC_TYPE_DRAWRECTP << 24) | (GDC_CMD_BLT_FILL << 16); + cmd[5] = (rect->dy << 16) | (rect->dx); + cmd[6] = (height << 16) | width; + + mb862xxfb_write_fifo(7, cmd, info); +} + +void mb862xxfb_init_accel(struct fb_info *info, int xres) +{ + struct mb862xxfb_par *par = info->par; + + if (info->var.bits_per_pixel == 32) { + info->fbops->fb_fillrect = cfb_fillrect; + info->fbops->fb_copyarea = cfb_copyarea; + info->fbops->fb_imageblit = cfb_imageblit; + } else { + outreg(disp, GC_L0EM, 3); + info->fbops->fb_fillrect = mb86290fb_fillrect; + info->fbops->fb_copyarea = mb86290fb_copyarea; + info->fbops->fb_imageblit = mb86290fb_imageblit; + } + outreg(draw, GDC_REG_DRAW_BASE, 0); + outreg(draw, GDC_REG_MODE_MISC, 0x8000); + outreg(draw, GDC_REG_X_RESOLUTION, xres); + + info->flags |= + FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | + FBINFO_HWACCEL_IMAGEBLIT; + info->fix.accel = 0xff; /*FIXME: add right define */ +} +EXPORT_SYMBOL(mb862xxfb_init_accel); diff --git a/drivers/video/mb862xx/mb862xxfb_accel.h b/drivers/video/mb862xx/mb862xxfb_accel.h new file mode 100644 index 00000000000..96a2dfef0f6 --- /dev/null +++ b/drivers/video/mb862xx/mb862xxfb_accel.h @@ -0,0 +1,203 @@ +#ifndef __MB826XXFB_ACCEL_H__ +#define __MB826XXFB_ACCEL_H__ + +/* registers */ +#define GDC_GEO_REG_INPUT_FIFO 0x00000400L + +/* Special Registers */ +#define GDC_REG_CTRL 0x00000400L +#define GDC_REG_FIFO_STATUS 0x00000404L +#define GDC_REG_FIFO_COUNT 0x00000408L +#define GDC_REG_SETUP_STATUS 0x0000040CL +#define GDC_REG_DDA_STATUS 0x00000410L +#define GDC_REG_ENGINE_STATUS 0x00000414L +#define GDC_REG_ERROR_STATUS 0x00000418L +#define GDC_REG_MODE_MISC 0x00000420L /* MDR0 */ +#define GDC_REG_MODE_LINE 0x00000424L /* MDR1 */ +#define GDC_REG_MODE_POLYGON 0x00000428L /* MDR2 */ +#define GDC_REG_MODE_TEXTURE 0x0000042CL /* MDR3 */ +#define GDC_REG_MODE_BITMAP 0x00000430L /* MDR4 */ +#define GDC_REG_MODE_EXTENSION 0x0000043CL /* MDR7 */ + +/* Configuration Registers */ +#define GDC_REG_DRAW_BASE 0x00000440L +#define GDC_REG_X_RESOLUTION 0x00000444L +#define GDC_REG_Z_BASE 0x00000448L +#define GDC_REG_TEXTURE_BASE 0x0000044CL +#define GDC_REG_POLYGON_FLAG_BASE 0x00000450L +#define GDC_REG_CLIP_XMIN 0x00000454L +#define GDC_REG_CLIP_XMAX 0x00000458L +#define GDC_REG_CLIP_YMIN 0x0000045CL +#define GDC_REG_CLIP_YMAX 0x00000460L +#define GDC_REG_TEXURE_SIZE 0x00000464L +#define GDC_REG_TILE_SIZE 0x00000468L +#define GDC_REG_TEX_BUF_OFFSET 0x0000046CL + +/* for MB86293 or later */ +#define GDC_REG_ALPHA_MAP_BASE 0x00000474L /* ABR */ + +/* Constant Registers */ +#define GDC_REG_FOREGROUND_COLOR 0x00000480L +#define GDC_REG_BACKGROUND_COLOR 0x00000484L +#define GDC_REG_ALPHA 0x00000488L +#define GDC_REG_LINE_PATTERN 0x0000048CL +#define GDC_REG_TEX_BORDER_COLOR 0x00000494L +#define GDC_REG_LINE_PATTERN_OFFSET 0x000003E0L + +/* Coomand Code */ +#define GDC_CMD_PIXEL 0x00000000L +#define GDC_CMD_PIXEL_Z 0x00000001L + +#define GDC_CMD_X_VECTOR 0x00000020L +#define GDC_CMD_Y_VECTOR 0x00000021L +#define GDC_CMD_X_VECTOR_NOEND 0x00000022L +#define GDC_CMD_Y_VECTOR_NOEND 0x00000023L +#define GDC_CMD_X_VECTOR_BLPO 0x00000024L +#define GDC_CMD_Y_VECTOR_BLPO 0x00000025L +#define GDC_CMD_X_VECTOR_NOEND_BLPO 0x00000026L +#define GDC_CMD_Y_VECTOR_NOEND_BLPO 0x00000027L +#define GDC_CMD_AA_X_VECTOR 0x00000028L +#define GDC_CMD_AA_Y_VECTOR 0x00000029L +#define GDC_CMD_AA_X_VECTOR_NOEND 0x0000002AL +#define GDC_CMD_AA_Y_VECTOR_NOEND 0x0000002BL +#define GDC_CMD_AA_X_VECTOR_BLPO 0x0000002CL +#define GDC_CMD_AA_Y_VECTOR_BLPO 0x0000002DL +#define GDC_CMD_AA_X_VECTOR_NOEND_BLPO 0x0000002EL +#define GDC_CMD_AA_Y_VECTOR_NOEND_BLPO 0x0000002FL + +#define GDC_CMD_0_VECTOR 0x00000030L +#define GDC_CMD_1_VECTOR 0x00000031L +#define GDC_CMD_0_VECTOR_NOEND 0x00000032L +#define GDC_CMD_1_VECTOR_NOEND 0x00000033L +#define GDC_CMD_0_VECTOR_BLPO 0x00000034L +#define GDC_CMD_1_VECTOR_BLPO 0x00000035L +#define GDC_CMD_0_VECTOR_NOEND_BLPO 0x00000036L +#define GDC_CMD_1_VECTOR_NOEND_BLPO 0x00000037L +#define GDC_CMD_AA_0_VECTOR 0x00000038L +#define GDC_CMD_AA_1_VECTOR 0x00000039L +#define GDC_CMD_AA_0_VECTOR_NOEND 0x0000003AL +#define GDC_CMD_AA_1_VECTOR_NOEND 0x0000003BL +#define GDC_CMD_AA_0_VECTOR_BLPO 0x0000003CL +#define GDC_CMD_AA_1_VECTOR_BLPO 0x0000003DL +#define GDC_CMD_AA_0_VECTOR_NOEND_BLPO 0x0000003EL +#define GDC_CMD_AA_1_VECTOR_NOEND_BLPO 0x0000003FL + +#define GDC_CMD_BLT_FILL 0x00000041L +#define GDC_CMD_BLT_DRAW 0x00000042L +#define GDC_CMD_BITMAP 0x00000043L +#define GDC_CMD_BLTCOPY_TOP_LEFT 0x00000044L +#define GDC_CMD_BLTCOPY_TOP_RIGHT 0x00000045L +#define GDC_CMD_BLTCOPY_BOTTOM_LEFT 0x00000046L +#define GDC_CMD_BLTCOPY_BOTTOM_RIGHT 0x00000047L +#define GDC_CMD_LOAD_TEXTURE 0x00000048L +#define GDC_CMD_LOAD_TILE 0x00000049L + +#define GDC_CMD_TRAP_RIGHT 0x00000060L +#define GDC_CMD_TRAP_LEFT 0x00000061L +#define GDC_CMD_TRIANGLE_FAN 0x00000062L +#define GDC_CMD_FLAG_TRIANGLE_FAN 0x00000063L + +#define GDC_CMD_FLUSH_FB 0x000000C1L +#define GDC_CMD_FLUSH_Z 0x000000C2L + +#define GDC_CMD_POLYGON_BEGIN 0x000000E0L +#define GDC_CMD_POLYGON_END 0x000000E1L +#define GDC_CMD_CLEAR_POLY_FLAG 0x000000E2L +#define GDC_CMD_NORMAL 0x000000FFL + +#define GDC_CMD_VECTOR_BLPO_FLAG 0x00040000L +#define GDC_CMD_FAST_VECTOR_BLPO_FLAG 0x00000004L + +/* for MB86293 or later */ +#define GDC_CMD_MDR1 0x00000000L +#define GDC_CMD_MDR1S 0x00000002L +#define GDC_CMD_MDR1B 0x00000004L +#define GDC_CMD_MDR2 0x00000001L +#define GDC_CMD_MDR2S 0x00000003L +#define GDC_CMD_MDR2TL 0x00000007L +#define GDC_CMD_GMDR1E 0x00000010L +#define GDC_CMD_GMDR2E 0x00000020L +#define GDC_CMD_OVERLAP_SHADOW_XY 0x00000000L +#define GDC_CMD_OVERLAP_SHADOW_XY_COMPOSITION 0x00000001L +#define GDC_CMD_OVERLAP_Z_PACKED_ONBS 0x00000007L +#define GDC_CMD_OVERLAP_Z_ORIGIN 0x00000000L +#define GDC_CMD_OVERLAP_Z_NON_TOPLEFT 0x00000001L +#define GDC_CMD_OVERLAP_Z_BORDER 0x00000002L +#define GDC_CMD_OVERLAP_Z_SHADOW 0x00000003L +#define GDC_CMD_BLTCOPY_ALT_ALPHA 0x00000000L /* Reserverd */ +#define GDC_CMD_DC_LOGOUT 0x00000000L /* Reserverd */ +#define GDC_CMD_BODY_FORE_COLOR 0x00000000L +#define GDC_CMD_BODY_BACK_COLOR 0x00000001L +#define GDC_CMD_SHADOW_FORE_COLOR 0x00000002L +#define GDC_CMD_SHADOW_BACK_COLOR 0x00000003L +#define GDC_CMD_BORDER_FORE_COLOR 0x00000004L +#define GDC_CMD_BORDER_BACK_COLOR 0x00000005L + +/* Type Code Table */ +#define GDC_TYPE_G_NOP 0x00000020L +#define GDC_TYPE_G_BEGIN 0x00000021L +#define GDC_TYPE_G_BEGINCONT 0x00000022L +#define GDC_TYPE_G_END 0x00000023L +#define GDC_TYPE_G_VERTEX 0x00000030L +#define GDC_TYPE_G_VERTEXLOG 0x00000032L +#define GDC_TYPE_G_VERTEXNOPLOG 0x00000033L +#define GDC_TYPE_G_INIT 0x00000040L +#define GDC_TYPE_G_VIEWPORT 0x00000041L +#define GDC_TYPE_G_DEPTHRANGE 0x00000042L +#define GDC_TYPE_G_LOADMATRIX 0x00000043L +#define GDC_TYPE_G_VIEWVOLUMEXYCLIP 0x00000044L +#define GDC_TYPE_G_VIEWVOLUMEZCLIP 0x00000045L +#define GDC_TYPE_G_VIEWVOLUMEWCLIP 0x00000046L +#define GDC_TYPE_SETLVERTEX2I 0x00000072L +#define GDC_TYPE_SETLVERTEX2IP 0x00000073L +#define GDC_TYPE_SETMODEREGISTER 0x000000C0L +#define GDC_TYPE_SETGMODEREGISTER 0x000000C1L +#define GDC_TYPE_OVERLAPXYOFFT 0x000000C8L +#define GDC_TYPE_OVERLAPZOFFT 0x000000C9L +#define GDC_TYPE_DC_LOGOUTADDR 0x000000CCL +#define GDC_TYPE_SETCOLORREGISTER 0x000000CEL +#define GDC_TYPE_G_BEGINE 0x000000E1L +#define GDC_TYPE_G_BEGINCONTE 0x000000E2L +#define GDC_TYPE_G_ENDE 0x000000E3L +#define GDC_TYPE_DRAWPIXEL 0x00000000L +#define GDC_TYPE_DRAWPIXELZ 0x00000001L +#define GDC_TYPE_DRAWLINE 0x00000002L +#define GDC_TYPE_DRAWLINE2I 0x00000003L +#define GDC_TYPE_DRAWLINE2IP 0x00000004L +#define GDC_TYPE_DRAWTRAP 0x00000005L +#define GDC_TYPE_DRAWVERTEX2I 0x00000006L +#define GDC_TYPE_DRAWVERTEX2IP 0x00000007L +#define GDC_TYPE_DRAWRECTP 0x00000009L +#define GDC_TYPE_DRAWBITMAPP 0x0000000BL +#define GDC_TYPE_BLTCOPYP 0x0000000DL +#define GDC_TYPE_BLTCOPYALTERNATEP 0x0000000FL +#define GDC_TYPE_LOADTEXTUREP 0x00000011L +#define GDC_TYPE_BLTTEXTUREP 0x00000013L +#define GDC_TYPE_BLTCOPYALTALPHABLENDP 0x0000001FL +#define GDC_TYPE_SETVERTEX2I 0x00000070L +#define GDC_TYPE_SETVERTEX2IP 0x00000071L +#define GDC_TYPE_DRAW 0x000000F0L +#define GDC_TYPE_SETREGISTER 0x000000F1L +#define GDC_TYPE_SYNC 0x000000FCL +#define GDC_TYPE_INTERRUPT 0x000000FDL +#define GDC_TYPE_NOP 0x0 + +/* Raster operation */ +#define GDC_ROP_CLEAR 0x0000 +#define GDC_ROP_AND 0x0001 +#define GDC_ROP_AND_REVERSE 0x0002 +#define GDC_ROP_COPY 0x0003 +#define GDC_ROP_AND_INVERTED 0x0004 +#define GDC_ROP_NOP 0x0005 +#define GDC_ROP_XOR 0x0006 +#define GDC_ROP_OR 0x0007 +#define GDC_ROP_NOR 0x0008 +#define GDC_ROP_EQUIV 0x0009 +#define GDC_ROP_INVERT 0x000A +#define GDC_ROP_OR_REVERSE 0x000B +#define GDC_ROP_COPY_INVERTED 0x000C +#define GDC_ROP_OR_INVERTED 0x000D +#define GDC_ROP_NAND 0x000E +#define GDC_ROP_SET 0x000F + +#endif diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 34e4e799516..0129f1bc352 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/fb.h> +#include <linux/kernel.h> #undef DEBUG @@ -402,21 +403,6 @@ const struct fb_videomode vesa_modes[] = { EXPORT_SYMBOL(vesa_modes); #endif /* CONFIG_FB_MODE_HELPERS */ -static int my_atoi(const char *name) -{ - int val = 0; - - for (;; name++) { - switch (*name) { - case '0' ... '9': - val = 10*val+(*name-'0'); - break; - default: - return val; - } - } -} - /** * fb_try_mode - test a video mode * @var: frame buffer user defined part of display @@ -539,7 +525,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, namelen = i; if (!refresh_specified && !bpp_specified && !yres_specified) { - refresh = my_atoi(&name[i+1]); + refresh = simple_strtol(&name[i+1], NULL, 10); refresh_specified = 1; if (cvt || rb) cvt = 0; @@ -549,7 +535,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, case '-': namelen = i; if (!bpp_specified && !yres_specified) { - bpp = my_atoi(&name[i+1]); + bpp = simple_strtol(&name[i+1], NULL, 10); bpp_specified = 1; if (cvt || rb) cvt = 0; @@ -558,7 +544,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, break; case 'x': if (!yres_specified) { - yres = my_atoi(&name[i+1]); + yres = simple_strtol(&name[i+1], NULL, 10); yres_specified = 1; } else goto done; @@ -586,7 +572,7 @@ int fb_find_mode(struct fb_var_screeninfo *var, } } if (i < 0 && yres_specified) { - xres = my_atoi(name); + xres = simple_strtol(name, NULL, 10); res_specified = 1; } done: diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 4d8c54c23dd..b043ac83c41 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -282,8 +282,17 @@ static int offb_set_par(struct fb_info *info) return 0; } +static void offb_destroy(struct fb_info *info) +{ + if (info->screen_base) + iounmap(info->screen_base); + release_mem_region(info->aperture_base, info->aperture_size); + framebuffer_release(info); +} + static struct fb_ops offb_ops = { .owner = THIS_MODULE, + .fb_destroy = offb_destroy, .fb_setcolreg = offb_setcolreg, .fb_set_par = offb_set_par, .fb_blank = offb_blank, @@ -482,10 +491,14 @@ static void __init offb_init_fb(const char *name, const char *full_name, var->sync = 0; var->vmode = FB_VMODE_NONINTERLACED; + /* set offb aperture size for generic probing */ + info->aperture_base = address; + info->aperture_size = fix->smem_len; + info->fbops = &offb_ops; info->screen_base = ioremap(address, fix->smem_len); info->pseudo_palette = (void *) (info + 1); - info->flags = FBINFO_DEFAULT | foreign_endian; + info->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE | foreign_endian; fb_alloc_cmap(&info->cmap, 256, 0); diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c index c7c6455f1fa..e192b058a68 100644 --- a/drivers/video/omap/dispc.c +++ b/drivers/video/omap/dispc.c @@ -189,11 +189,6 @@ static struct { struct omapfb_color_key color_key; } dispc; -static struct platform_device omapdss_device = { - .name = "omapdss", - .id = -1, -}; - static void enable_lcd_clocks(int enable); static void inline dispc_write_reg(int idx, u32 val) @@ -920,20 +915,20 @@ static irqreturn_t omap_dispc_irq_handler(int irq, void *dev) static int get_dss_clocks(void) { - dispc.dss_ick = clk_get(&omapdss_device.dev, "ick"); + dispc.dss_ick = clk_get(&dispc.fbdev->dssdev->dev, "ick"); if (IS_ERR(dispc.dss_ick)) { dev_err(dispc.fbdev->dev, "can't get ick\n"); return PTR_ERR(dispc.dss_ick); } - dispc.dss1_fck = clk_get(&omapdss_device.dev, "dss1_fck"); + dispc.dss1_fck = clk_get(&dispc.fbdev->dssdev->dev, "dss1_fck"); if (IS_ERR(dispc.dss1_fck)) { dev_err(dispc.fbdev->dev, "can't get dss1_fck\n"); clk_put(dispc.dss_ick); return PTR_ERR(dispc.dss1_fck); } - dispc.dss_54m_fck = clk_get(&omapdss_device.dev, "tv_fck"); + dispc.dss_54m_fck = clk_get(&dispc.fbdev->dssdev->dev, "tv_fck"); if (IS_ERR(dispc.dss_54m_fck)) { dev_err(dispc.fbdev->dev, "can't get tv_fck\n"); clk_put(dispc.dss_ick); @@ -1385,12 +1380,6 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode, int skip_init = 0; int i; - r = platform_device_register(&omapdss_device); - if (r) { - dev_err(fbdev->dev, "can't register omapdss device\n"); - return r; - } - memset(&dispc, 0, sizeof(dispc)); dispc.base = ioremap(DISPC_BASE, SZ_1K); @@ -1534,7 +1523,6 @@ static void omap_dispc_cleanup(void) free_irq(INT_24XX_DSS_IRQ, dispc.fbdev); put_dss_clocks(); iounmap(dispc.base); - platform_device_unregister(&omapdss_device); } const struct lcd_ctrl omap2_int_ctrl = { diff --git a/drivers/video/omap/lcd_2430sdp.c b/drivers/video/omap/lcd_2430sdp.c index 760645d9dbb..e3eccc9af78 100644 --- a/drivers/video/omap/lcd_2430sdp.c +++ b/drivers/video/omap/lcd_2430sdp.c @@ -25,7 +25,7 @@ #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/gpio.h> -#include <linux/i2c/twl4030.h> +#include <linux/i2c/twl.h> #include <plat/mux.h> #include <asm/mach-types.h> @@ -52,7 +52,7 @@ static unsigned enable_gpio; #define TWL4030_VPLL2_DEV_GRP 0x33 #define TWL4030_VPLL2_DEDICATED 0x36 -#define t2_out(c, r, v) twl4030_i2c_write_u8(c, r, v) +#define t2_out(c, r, v) twl_i2c_write_u8(c, r, v) static int sdp2430_panel_init(struct lcd_panel *panel, diff --git a/drivers/video/omap/lcd_htcherald.c b/drivers/video/omap/lcd_htcherald.c index a9007c5d1fa..4802419da83 100644 --- a/drivers/video/omap/lcd_htcherald.c +++ b/drivers/video/omap/lcd_htcherald.c @@ -115,12 +115,12 @@ struct platform_driver htcherald_panel_driver = { }, }; -static int htcherald_panel_drv_init(void) +static int __init htcherald_panel_drv_init(void) { return platform_driver_register(&htcherald_panel_driver); } -static void htcherald_panel_drv_cleanup(void) +static void __exit htcherald_panel_drv_cleanup(void) { platform_driver_unregister(&htcherald_panel_driver); } diff --git a/drivers/video/omap/lcd_ldp.c b/drivers/video/omap/lcd_ldp.c index 5bb7f6f1460..0f5952cae85 100644 --- a/drivers/video/omap/lcd_ldp.c +++ b/drivers/video/omap/lcd_ldp.c @@ -24,7 +24,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/delay.h> -#include <linux/i2c/twl4030.h> +#include <linux/i2c/twl.h> #include <mach/gpio.h> #include <plat/mux.h> @@ -59,7 +59,7 @@ #define TWL4030_VPLL2_DEV_GRP 0x33 #define TWL4030_VPLL2_DEDICATED 0x36 -#define t2_out(c, r, v) twl4030_i2c_write_u8(c, r, v) +#define t2_out(c, r, v) twl_i2c_write_u8(c, r, v) static int ldp_panel_init(struct lcd_panel *panel, diff --git a/drivers/video/omap/lcd_omap2evm.c b/drivers/video/omap/lcd_omap2evm.c index 006c2fe7360..7e7a65c0845 100644 --- a/drivers/video/omap/lcd_omap2evm.c +++ b/drivers/video/omap/lcd_omap2evm.c @@ -24,7 +24,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/gpio.h> -#include <linux/i2c/twl4030.h> +#include <linux/i2c/twl.h> #include <plat/mux.h> #include <asm/mach-types.h> @@ -61,9 +61,9 @@ static int omap2evm_panel_init(struct lcd_panel *panel, gpio_direction_output(LCD_PANEL_LR, 1); gpio_direction_output(LCD_PANEL_UD, 1); - twl4030_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN); - twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON); - twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF); + twl_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN); + twl_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON); + twl_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF); bklight_level = 100; return 0; @@ -101,7 +101,7 @@ static int omap2evm_bklight_setlevel(struct lcd_panel *panel, u8 c; if ((level >= 0) && (level <= 100)) { c = (125 * (100 - level)) / 100 + 2; - twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, c, TWL_PWMA_PWMAOFF); + twl_i2c_write_u8(TWL4030_MODULE_PWMA, c, TWL_PWMA_PWMAOFF); bklight_level = level; } return 0; diff --git a/drivers/video/omap/lcd_omap3beagle.c b/drivers/video/omap/lcd_omap3beagle.c index fc503d8f3c2..ca75cc2a87a 100644 --- a/drivers/video/omap/lcd_omap3beagle.c +++ b/drivers/video/omap/lcd_omap3beagle.c @@ -23,7 +23,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/gpio.h> -#include <linux/i2c/twl4030.h> +#include <linux/i2c/twl.h> #include <plat/mux.h> #include <plat/mux.h> diff --git a/drivers/video/omap/lcd_omap3evm.c b/drivers/video/omap/lcd_omap3evm.c index ae2edc4081a..06840da0b09 100644 --- a/drivers/video/omap/lcd_omap3evm.c +++ b/drivers/video/omap/lcd_omap3evm.c @@ -23,7 +23,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/gpio.h> -#include <linux/i2c/twl4030.h> +#include <linux/i2c/twl.h> #include <plat/mux.h> #include <asm/mach-types.h> @@ -63,9 +63,9 @@ static int omap3evm_panel_init(struct lcd_panel *panel, gpio_direction_output(LCD_PANEL_LR, 1); gpio_direction_output(LCD_PANEL_UD, 1); - twl4030_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN); - twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON); - twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF); + twl_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN); + twl_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON); + twl_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF); bklight_level = 100; return 0; @@ -102,7 +102,7 @@ static int omap3evm_bklight_setlevel(struct lcd_panel *panel, u8 c; if ((level >= 0) && (level <= 100)) { c = (125 * (100 - level)) / 100 + 2; - twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, c, TWL_PWMA_PWMAOFF); + twl_i2c_write_u8(TWL4030_MODULE_PWMA, c, TWL_PWMA_PWMAOFF); bklight_level = level; } return 0; diff --git a/drivers/video/omap/lcd_overo.c b/drivers/video/omap/lcd_overo.c index 56ee192e9ee..564933ffac6 100644 --- a/drivers/video/omap/lcd_overo.c +++ b/drivers/video/omap/lcd_overo.c @@ -21,7 +21,7 @@ #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/i2c/twl4030.h> +#include <linux/i2c/twl.h> #include <mach/gpio.h> #include <plat/mux.h> diff --git a/drivers/video/omap/lcdc.c b/drivers/video/omap/lcdc.c index b831e1df629..a33483910dc 100644 --- a/drivers/video/omap/lcdc.c +++ b/drivers/video/omap/lcdc.c @@ -29,6 +29,7 @@ #include <linux/vmalloc.h> #include <linux/clk.h> +#include <mach/lcdc.h> #include <plat/dma.h> #include <asm/mach-types.h> @@ -39,38 +40,6 @@ #define MODULE_NAME "lcdc" -#define OMAP_LCDC_BASE 0xfffec000 -#define OMAP_LCDC_SIZE 256 -#define OMAP_LCDC_IRQ INT_LCD_CTRL - -#define OMAP_LCDC_CONTROL (OMAP_LCDC_BASE + 0x00) -#define OMAP_LCDC_TIMING0 (OMAP_LCDC_BASE + 0x04) -#define OMAP_LCDC_TIMING1 (OMAP_LCDC_BASE + 0x08) -#define OMAP_LCDC_TIMING2 (OMAP_LCDC_BASE + 0x0c) -#define OMAP_LCDC_STATUS (OMAP_LCDC_BASE + 0x10) -#define OMAP_LCDC_SUBPANEL (OMAP_LCDC_BASE + 0x14) -#define OMAP_LCDC_LINE_INT (OMAP_LCDC_BASE + 0x18) -#define OMAP_LCDC_DISPLAY_STATUS (OMAP_LCDC_BASE + 0x1c) - -#define OMAP_LCDC_STAT_DONE (1 << 0) -#define OMAP_LCDC_STAT_VSYNC (1 << 1) -#define OMAP_LCDC_STAT_SYNC_LOST (1 << 2) -#define OMAP_LCDC_STAT_ABC (1 << 3) -#define OMAP_LCDC_STAT_LINE_INT (1 << 4) -#define OMAP_LCDC_STAT_FUF (1 << 5) -#define OMAP_LCDC_STAT_LOADED_PALETTE (1 << 6) - -#define OMAP_LCDC_CTRL_LCD_EN (1 << 0) -#define OMAP_LCDC_CTRL_LCD_TFT (1 << 7) -#define OMAP_LCDC_CTRL_LINE_IRQ_CLR_SEL (1 << 10) - -#define OMAP_LCDC_IRQ_VSYNC (1 << 2) -#define OMAP_LCDC_IRQ_DONE (1 << 3) -#define OMAP_LCDC_IRQ_LOADED_PALETTE (1 << 4) -#define OMAP_LCDC_IRQ_LINE_NIRQ (1 << 5) -#define OMAP_LCDC_IRQ_LINE (1 << 6) -#define OMAP_LCDC_IRQ_MASK (((1 << 5) - 1) << 2) - #define MAX_PALETTE_SIZE PAGE_SIZE enum lcdc_load_mode { diff --git a/drivers/video/omap/omapfb.h b/drivers/video/omap/omapfb.h index 46e4714014e..af3c9e571ec 100644 --- a/drivers/video/omap/omapfb.h +++ b/drivers/video/omap/omapfb.h @@ -203,6 +203,8 @@ struct omapfb_device { struct omapfb_mem_desc mem_desc; struct fb_info *fb_info[OMAPFB_PLANE_NUM]; + + struct platform_device *dssdev; /* dummy dev for clocks */ }; #ifdef CONFIG_ARCH_OMAP1 diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c index c7f59a5ccdb..2c4f470fa08 100644 --- a/drivers/video/omap/omapfb_main.c +++ b/drivers/video/omap/omapfb_main.c @@ -83,6 +83,19 @@ static struct caps_table_struct color_caps[] = { { 1 << OMAPFB_COLOR_YUY422, "YUY422", }, }; +static void omapdss_release(struct device *dev) +{ +} + +/* dummy device for clocks */ +static struct platform_device omapdss_device = { + .name = "omapdss", + .id = -1, + .dev = { + .release = omapdss_release, + }, +}; + /* * --------------------------------------------------------------------------- * LCD panel @@ -1700,6 +1713,7 @@ static int omapfb_do_probe(struct platform_device *pdev, fbdev->dev = &pdev->dev; fbdev->panel = panel; + fbdev->dssdev = &omapdss_device; platform_set_drvdata(pdev, fbdev); mutex_init(&fbdev->rqueue_mutex); @@ -1814,8 +1828,16 @@ cleanup: static int omapfb_probe(struct platform_device *pdev) { + int r; + BUG_ON(fbdev_pdev != NULL); + r = platform_device_register(&omapdss_device); + if (r) { + dev_err(&pdev->dev, "can't register omapdss device\n"); + return r; + } + /* Delay actual initialization until the LCD is registered */ fbdev_pdev = pdev; if (fbdev_panel != NULL) @@ -1843,6 +1865,9 @@ static int omapfb_remove(struct platform_device *pdev) fbdev->state = OMAPFB_DISABLED; omapfb_free_resources(fbdev, saved_state); + platform_device_unregister(&omapdss_device); + fbdev->dssdev = NULL; + return 0; } diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c index fed7b1bda19..1162603c72e 100644 --- a/drivers/video/omap/rfbi.c +++ b/drivers/video/omap/rfbi.c @@ -83,13 +83,13 @@ static inline u32 rfbi_read_reg(int idx) static int rfbi_get_clocks(void) { - rfbi.dss_ick = clk_get(rfbi.fbdev->dev, "ick"); + rfbi.dss_ick = clk_get(&dispc.fbdev->dssdev->dev, "ick"); if (IS_ERR(rfbi.dss_ick)) { dev_err(rfbi.fbdev->dev, "can't get ick\n"); return PTR_ERR(rfbi.dss_ick); } - rfbi.dss1_fck = clk_get(rfbi.fbdev->dev, "dss1_fck"); + rfbi.dss1_fck = clk_get(&dispc.fbdev->dssdev->dev, "dss1_fck"); if (IS_ERR(rfbi.dss1_fck)) { dev_err(rfbi.fbdev->dev, "can't get dss1_fck\n"); clk_put(rfbi.dss_ick); diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index 71d8dec3063..c63ce767b27 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -25,6 +25,13 @@ config OMAP2_DSS_DEBUG_SUPPORT This enables debug messages. You need to enable printing with 'debug' module parameter. +config OMAP2_DSS_COLLECT_IRQ_STATS + bool "Collect DSS IRQ statistics" + depends on OMAP2_DSS_DEBUG_SUPPORT + default n + help + Collect DSS IRQ statistics, printable via debugfs + config OMAP2_DSS_RFBI bool "RFBI support" default n diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 29497a0c9a9..82918eec6d2 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -124,6 +124,7 @@ static void restore_all_ctx(void) dss_clk_disable_all_no_ctx(); } +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) /* CLOCKS */ static void core_dump_clocks(struct seq_file *s) { @@ -149,6 +150,7 @@ static void core_dump_clocks(struct seq_file *s) clocks[i]->usecount); } } +#endif /* defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) */ static int dss_get_clock(struct clk **clock, const char *clk_name) { @@ -395,6 +397,14 @@ static int dss_initialize_debugfs(void) debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir, &dss_debug_dump_clocks, &dss_debug_fops); + debugfs_create_file("dispc_irq", S_IRUGO, dss_debugfs_dir, + &dispc_dump_irqs, &dss_debug_fops); + +#ifdef CONFIG_OMAP2_DSS_DSI + debugfs_create_file("dsi_irq", S_IRUGO, dss_debugfs_dir, + &dsi_dump_irqs, &dss_debug_fops); +#endif + debugfs_create_file("dss", S_IRUGO, dss_debugfs_dir, &dss_dump_regs, &dss_debug_fops); debugfs_create_file("dispc", S_IRUGO, dss_debugfs_dir, diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 6dabf4b2f00..de8bfbac9e2 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -148,6 +148,12 @@ static const struct dispc_reg dispc_reg_att[] = { DISPC_GFX_ATTRIBUTES, DISPC_VID_ATTRIBUTES(0), DISPC_VID_ATTRIBUTES(1) }; +struct dispc_irq_stats { + unsigned long last_reset; + unsigned irq_count; + unsigned irqs[32]; +}; + static struct { void __iomem *base; @@ -160,6 +166,11 @@ static struct { struct work_struct error_work; u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; + +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS + spinlock_t irq_stats_lock; + struct dispc_irq_stats irq_stats; +#endif } dispc; static void _omap_dispc_set_irqs(void); @@ -1443,7 +1454,10 @@ static unsigned long calc_fclk_five_taps(u16 width, u16 height, do_div(tmp, 2 * out_height * ppl); fclk = tmp; - if (height > 2 * out_height && ppl != out_width) { + if (height > 2 * out_height) { + if (ppl == out_width) + return 0; + tmp = pclk * (height - 2 * out_height) * out_width; do_div(tmp, 2 * out_height * (ppl - out_width)); fclk = max(fclk, (u32) tmp); @@ -1623,7 +1637,7 @@ static int _dispc_setup_plane(enum omap_plane plane, DSSDBG("required fclk rate = %lu Hz\n", fclk); DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate()); - if (fclk > dispc_fclk_rate()) { + if (!fclk || fclk > dispc_fclk_rate()) { DSSERR("failed to set up scaling, " "required fclk rate = %lu Hz, " "current fclk rate = %lu Hz\n", @@ -2247,6 +2261,50 @@ void dispc_dump_clocks(struct seq_file *s) enable_clocks(0); } +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS +void dispc_dump_irqs(struct seq_file *s) +{ + unsigned long flags; + struct dispc_irq_stats stats; + + spin_lock_irqsave(&dispc.irq_stats_lock, flags); + + stats = dispc.irq_stats; + memset(&dispc.irq_stats, 0, sizeof(dispc.irq_stats)); + dispc.irq_stats.last_reset = jiffies; + + spin_unlock_irqrestore(&dispc.irq_stats_lock, flags); + + seq_printf(s, "period %u ms\n", + jiffies_to_msecs(jiffies - stats.last_reset)); + + seq_printf(s, "irqs %d\n", stats.irq_count); +#define PIS(x) \ + seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]); + + PIS(FRAMEDONE); + PIS(VSYNC); + PIS(EVSYNC_EVEN); + PIS(EVSYNC_ODD); + PIS(ACBIAS_COUNT_STAT); + PIS(PROG_LINE_NUM); + PIS(GFX_FIFO_UNDERFLOW); + PIS(GFX_END_WIN); + PIS(PAL_GAMMA_MASK); + PIS(OCP_ERR); + PIS(VID1_FIFO_UNDERFLOW); + PIS(VID1_END_WIN); + PIS(VID2_FIFO_UNDERFLOW); + PIS(VID2_END_WIN); + PIS(SYNC_LOST); + PIS(SYNC_LOST_DIGIT); + PIS(WAKEUP); +#undef PIS +} +#else +void dispc_dump_irqs(struct seq_file *s) { } +#endif + void dispc_dump_regs(struct seq_file *s) { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dispc_read_reg(r)) @@ -2665,6 +2723,13 @@ void dispc_irq_handler(void) irqstatus = dispc_read_reg(DISPC_IRQSTATUS); +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS + spin_lock(&dispc.irq_stats_lock); + dispc.irq_stats.irq_count++; + dss_collect_irq_stats(irqstatus, dispc.irq_stats.irqs); + spin_unlock(&dispc.irq_stats_lock); +#endif + #ifdef DEBUG if (dss_debug) print_irq_status(irqstatus); @@ -3012,6 +3077,11 @@ int dispc_init(void) spin_lock_init(&dispc.irq_lock); +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS + spin_lock_init(&dispc.irq_stats_lock); + dispc.irq_stats.last_reset = jiffies; +#endif + INIT_WORK(&dispc.error_work, dispc_error_worker); dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS); diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 5936487b5de..6122178f5f8 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -204,6 +204,14 @@ struct dsi_update_region { struct omap_dss_device *device; }; +struct dsi_irq_stats { + unsigned long last_reset; + unsigned irq_count; + unsigned dsi_irqs[32]; + unsigned vc_irqs[4][32]; + unsigned cio_irqs[32]; +}; + static struct { void __iomem *base; @@ -258,6 +266,11 @@ static struct #endif int debug_read; int debug_write; + +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS + spinlock_t irq_stats_lock; + struct dsi_irq_stats irq_stats; +#endif } dsi; #ifdef DEBUG @@ -528,6 +541,12 @@ void dsi_irq_handler(void) irqstatus = dsi_read_reg(DSI_IRQSTATUS); +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS + spin_lock(&dsi.irq_stats_lock); + dsi.irq_stats.irq_count++; + dss_collect_irq_stats(irqstatus, dsi.irq_stats.dsi_irqs); +#endif + if (irqstatus & DSI_IRQ_ERROR_MASK) { DSSERR("DSI error, irqstatus %x\n", irqstatus); print_irq_status(irqstatus); @@ -549,6 +568,10 @@ void dsi_irq_handler(void) vcstatus = dsi_read_reg(DSI_VC_IRQSTATUS(i)); +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS + dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]); +#endif + if (vcstatus & DSI_VC_IRQ_BTA) complete(&dsi.bta_completion); @@ -568,6 +591,10 @@ void dsi_irq_handler(void) if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) { ciostatus = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS); +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS + dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs); +#endif + dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, ciostatus); /* flush posted write */ dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS); @@ -579,6 +606,10 @@ void dsi_irq_handler(void) dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK); /* flush posted write */ dsi_read_reg(DSI_IRQSTATUS); + +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS + spin_unlock(&dsi.irq_stats_lock); +#endif } @@ -797,12 +828,12 @@ static int dsi_pll_power(enum dsi_pll_power_state state) /* PLL_PWR_STATUS */ while (FLD_GET(dsi_read_reg(DSI_CLK_CTRL), 29, 28) != state) { - udelay(1); - if (t++ > 1000) { + if (++t > 1000) { DSSERR("Failed to set DSI PLL power mode to %d\n", state); return -ENODEV; } + udelay(1); } return 0; @@ -1226,6 +1257,95 @@ void dsi_dump_clocks(struct seq_file *s) enable_clocks(0); } +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS +void dsi_dump_irqs(struct seq_file *s) +{ + unsigned long flags; + struct dsi_irq_stats stats; + + spin_lock_irqsave(&dsi.irq_stats_lock, flags); + + stats = dsi.irq_stats; + memset(&dsi.irq_stats, 0, sizeof(dsi.irq_stats)); + dsi.irq_stats.last_reset = jiffies; + + spin_unlock_irqrestore(&dsi.irq_stats_lock, flags); + + seq_printf(s, "period %u ms\n", + jiffies_to_msecs(jiffies - stats.last_reset)); + + seq_printf(s, "irqs %d\n", stats.irq_count); +#define PIS(x) \ + seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]); + + seq_printf(s, "-- DSI interrupts --\n"); + PIS(VC0); + PIS(VC1); + PIS(VC2); + PIS(VC3); + PIS(WAKEUP); + PIS(RESYNC); + PIS(PLL_LOCK); + PIS(PLL_UNLOCK); + PIS(PLL_RECALL); + PIS(COMPLEXIO_ERR); + PIS(HS_TX_TIMEOUT); + PIS(LP_RX_TIMEOUT); + PIS(TE_TRIGGER); + PIS(ACK_TRIGGER); + PIS(SYNC_LOST); + PIS(LDO_POWER_GOOD); + PIS(TA_TIMEOUT); +#undef PIS + +#define PIS(x) \ + seq_printf(s, "%-20s %10d %10d %10d %10d\n", #x, \ + stats.vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \ + stats.vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \ + stats.vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \ + stats.vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]); + + seq_printf(s, "-- VC interrupts --\n"); + PIS(CS); + PIS(ECC_CORR); + PIS(PACKET_SENT); + PIS(FIFO_TX_OVF); + PIS(FIFO_RX_OVF); + PIS(BTA); + PIS(ECC_NO_CORR); + PIS(FIFO_TX_UDF); + PIS(PP_BUSY_CHANGE); +#undef PIS + +#define PIS(x) \ + seq_printf(s, "%-20s %10d\n", #x, \ + stats.cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]); + + seq_printf(s, "-- CIO interrupts --\n"); + PIS(ERRSYNCESC1); + PIS(ERRSYNCESC2); + PIS(ERRSYNCESC3); + PIS(ERRESC1); + PIS(ERRESC2); + PIS(ERRESC3); + PIS(ERRCONTROL1); + PIS(ERRCONTROL2); + PIS(ERRCONTROL3); + PIS(STATEULPS1); + PIS(STATEULPS2); + PIS(STATEULPS3); + PIS(ERRCONTENTIONLP0_1); + PIS(ERRCONTENTIONLP1_1); + PIS(ERRCONTENTIONLP0_2); + PIS(ERRCONTENTIONLP1_2); + PIS(ERRCONTENTIONLP0_3); + PIS(ERRCONTENTIONLP1_3); + PIS(ULPSACTIVENOT_ALL0); + PIS(ULPSACTIVENOT_ALL1); +#undef PIS +} +#endif + void dsi_dump_regs(struct seq_file *s) { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(r)) @@ -1321,12 +1441,12 @@ static int dsi_complexio_power(enum dsi_complexio_power_state state) /* PWR_STATUS */ while (FLD_GET(dsi_read_reg(DSI_COMPLEXIO_CFG1), 26, 25) != state) { - udelay(1); - if (t++ > 1000) { + if (++t > 1000) { DSSERR("failed to set complexio power state to " "%d\n", state); return -ENODEV; } + udelay(1); } return 0; @@ -1526,10 +1646,10 @@ static void dsi_complexio_uninit(void) static int _dsi_wait_reset(void) { - int i = 0; + int t = 0; while (REG_GET(DSI_SYSSTATUS, 0, 0) == 0) { - if (i++ > 5) { + if (++t > 5) { DSSERR("soft reset failed\n"); return -ENODEV; } @@ -1999,7 +2119,7 @@ static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc) return -EINVAL; } - data_id = data_type | channel << 6; + data_id = data_type | dsi.vc[channel].dest_per << 6; r = (data_id << 0) | (data << 8) | (ecc << 24); @@ -2011,7 +2131,7 @@ static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc) int dsi_vc_send_null(int channel) { u8 nullpkg[] = {0, 0, 0, 0}; - return dsi_vc_send_long(0, DSI_DT_NULL_PACKET, nullpkg, 4, 0); + return dsi_vc_send_long(channel, DSI_DT_NULL_PACKET, nullpkg, 4, 0); } EXPORT_SYMBOL(dsi_vc_send_null); @@ -2058,7 +2178,7 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen) int r; if (dsi.debug_read) - DSSDBG("dsi_vc_dcs_read(ch%d, dcs_cmd %u)\n", channel, dcs_cmd); + DSSDBG("dsi_vc_dcs_read(ch%d, dcs_cmd %x)\n", channel, dcs_cmd); r = dsi_vc_send_short(channel, DSI_DT_DCS_READ, dcs_cmd, 0); if (r) @@ -2586,7 +2706,6 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev, /* using fifo not empty */ /* TX_FIFO_NOT_EMPTY */ while (FLD_GET(dsi_read_reg(DSI_VC_CTRL(0)), 5, 5)) { - udelay(1); fifo_stalls++; if (fifo_stalls > 0xfffff) { DSSERR("fifo stalls overflow, pixels left %d\n", @@ -2594,6 +2713,7 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev, dsi_if_enable(0); return -EIO; } + udelay(1); } #elif 1 /* using fifo emptiness */ @@ -2812,11 +2932,15 @@ static int dsi_set_update_mode(struct omap_dss_device *dssdev, static int dsi_set_te(struct omap_dss_device *dssdev, bool enable) { - int r; - r = dssdev->driver->enable_te(dssdev, enable); - /* XXX for some reason, DSI TE breaks if we don't wait here. - * Panel bug? Needs more studying */ - msleep(100); + int r = 0; + + if (dssdev->driver->enable_te) { + r = dssdev->driver->enable_te(dssdev, enable); + /* XXX for some reason, DSI TE breaks if we don't wait here. + * Panel bug? Needs more studying */ + msleep(100); + } + return r; } @@ -3637,6 +3761,11 @@ int dsi_init(struct platform_device *pdev) spin_lock_init(&dsi.errors_lock); dsi.errors = 0; +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS + spin_lock_init(&dsi.irq_stats_lock); + dsi.irq_stats.last_reset = jiffies; +#endif + init_completion(&dsi.bta_completion); init_completion(&dsi.update_completion); diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 9b05ee65a15..0a26b7d84d4 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -467,14 +467,14 @@ static irqreturn_t dss_irq_handler_omap3(int irq, void *arg) static int _omap_dss_wait_reset(void) { - unsigned timeout = 1000; + int t = 0; while (REG_GET(DSS_SYSSTATUS, 0, 0) == 0) { - udelay(1); - if (!--timeout) { + if (++t > 1000) { DSSERR("soft reset failed\n"); return -ENODEV; } + udelay(1); } return 0; diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 8da5ac42151..2bcb1245d6c 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -240,6 +240,7 @@ int dsi_init(struct platform_device *pdev); void dsi_exit(void); void dsi_dump_clocks(struct seq_file *s); +void dsi_dump_irqs(struct seq_file *s); void dsi_dump_regs(struct seq_file *s); void dsi_save_context(void); @@ -268,6 +269,7 @@ int dpi_init_display(struct omap_dss_device *dssdev); int dispc_init(void); void dispc_exit(void); void dispc_dump_clocks(struct seq_file *s); +void dispc_dump_irqs(struct seq_file *s); void dispc_dump_regs(struct seq_file *s); void dispc_irq_handler(void); void dispc_fake_vsync_irq(void); @@ -367,4 +369,16 @@ void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t); unsigned long rfbi_get_max_tx_rate(void); int rfbi_init_display(struct omap_dss_device *display); + +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS +static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr) +{ + int b; + for (b = 0; b < 32; ++b) { + if (irqstatus & (1 << b)) + irq_arr[b]++; + } +} +#endif + #endif diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index d0b3006ad8a..b936495c065 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -120,7 +120,7 @@ static struct { struct omap_dss_device *dssdev[2]; - struct kfifo *cmd_fifo; + struct kfifo cmd_fifo; spinlock_t cmd_lock; struct completion cmd_done; atomic_t cmd_fifo_full; @@ -1011,20 +1011,20 @@ static void process_cmd_fifo(void) return; while (true) { - spin_lock_irqsave(rfbi.cmd_fifo->lock, flags); + spin_lock_irqsave(&rfbi.cmd_lock, flags); - len = __kfifo_get(rfbi.cmd_fifo, (unsigned char *)&p, + len = kfifo_out(&rfbi.cmd_fifo, (unsigned char *)&p, sizeof(struct update_param)); if (len == 0) { DSSDBG("nothing more in fifo\n"); atomic_set(&rfbi.cmd_pending, 0); - spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags); + spin_unlock_irqrestore(&rfbi.cmd_lock, flags); break; } /* DSSDBG("fifo full %d\n", rfbi.cmd_fifo_full.counter);*/ - spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags); + spin_unlock_irqrestore(&rfbi.cmd_lock, flags); BUG_ON(len != sizeof(struct update_param)); BUG_ON(p.rfbi_module > 1); @@ -1052,25 +1052,25 @@ static void rfbi_push_cmd(struct update_param *p) unsigned long flags; int available; - spin_lock_irqsave(rfbi.cmd_fifo->lock, flags); + spin_lock_irqsave(&rfbi.cmd_lock, flags); available = RFBI_CMD_FIFO_LEN_BYTES - - __kfifo_len(rfbi.cmd_fifo); + kfifo_len(&rfbi.cmd_fifo); /* DSSDBG("%d bytes left in fifo\n", available); */ if (available < sizeof(struct update_param)) { DSSDBG("Going to wait because FIFO FULL..\n"); - spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags); + spin_unlock_irqrestore(&rfbi.cmd_lock, flags); atomic_inc(&rfbi.cmd_fifo_full); wait_for_completion(&rfbi.cmd_done); /*DSSDBG("Woke up because fifo not full anymore\n");*/ continue; } - ret = __kfifo_put(rfbi.cmd_fifo, (unsigned char *)p, + ret = kfifo_in(&rfbi.cmd_fifo, (unsigned char *)p, sizeof(struct update_param)); /* DSSDBG("pushed %d bytes\n", ret);*/ - spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags); + spin_unlock_irqrestore(&rfbi.cmd_lock, flags); BUG_ON(ret != sizeof(struct update_param)); @@ -1155,12 +1155,12 @@ int rfbi_init(void) { u32 rev; u32 l; + int r; spin_lock_init(&rfbi.cmd_lock); - rfbi.cmd_fifo = kfifo_alloc(RFBI_CMD_FIFO_LEN_BYTES, GFP_KERNEL, - &rfbi.cmd_lock); - if (IS_ERR(rfbi.cmd_fifo)) - return -ENOMEM; + r = kfifo_alloc(&rfbi.cmd_fifo, RFBI_CMD_FIFO_LEN_BYTES, GFP_KERNEL); + if (r) + return r; init_completion(&rfbi.cmd_done); atomic_set(&rfbi.cmd_fifo_full, 0); @@ -1196,7 +1196,7 @@ void rfbi_exit(void) { DSSDBG("rfbi_exit\n"); - kfifo_free(rfbi.cmd_fifo); + kfifo_free(&rfbi.cmd_fifo); iounmap(rfbi.base); } diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index ef299839858..d17caef6915 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -1311,6 +1311,7 @@ static void omapfb_free_fbmem(struct fb_info *fbi) if (rg->vrfb.vaddr[0]) { iounmap(rg->vrfb.vaddr[0]); omap_vrfb_release_ctx(&rg->vrfb); + rg->vrfb.vaddr[0] = NULL; } } @@ -2114,6 +2115,11 @@ static int omapfb_probe(struct platform_device *pdev) dssdev = NULL; for_each_dss_dev(dssdev) { omap_dss_get_device(dssdev); + if (!dssdev->driver) { + dev_err(&pdev->dev, "no driver for display\n"); + r = -EINVAL; + goto cleanup; + } fbdev->displays[fbdev->num_displays++] = dssdev; } diff --git a/drivers/video/output.c b/drivers/video/output.c index 5e6439ae739..5137aa016b8 100644 --- a/drivers/video/output.c +++ b/drivers/video/output.c @@ -50,7 +50,7 @@ static ssize_t video_output_store_state(struct device *dev, int request_state = simple_strtoul(buf,&endp,0); size_t size = endp - buf; - if (*endp && isspace(*endp)) + if (isspace(*endp)) size++; if (size != count) return -EINVAL; diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c index 0573ec685a5..0f361b6100d 100644 --- a/drivers/video/pmag-ba-fb.c +++ b/drivers/video/pmag-ba-fb.c @@ -98,7 +98,8 @@ static int pmagbafb_setcolreg(unsigned int regno, unsigned int red, { struct pmagbafb_par *par = info->par; - BUG_ON(regno >= info->cmap.len); + if (regno >= info->cmap.len) + return 1; red >>= 8; /* The cmap fields are 16 bits */ green >>= 8; /* wide, but the hardware colormap */ diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c index 98748723af9..2de0806421b 100644 --- a/drivers/video/pmagb-b-fb.c +++ b/drivers/video/pmagb-b-fb.c @@ -102,7 +102,8 @@ static int pmagbbfb_setcolreg(unsigned int regno, unsigned int red, { struct pmagbbfb_par *par = info->par; - BUG_ON(regno >= info->cmap.len); + if (regno >= info->cmap.len) + return 1; red >>= 8; /* The cmap fields are 16 bits */ green >>= 8; /* wide, but the hardware colormap */ diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index f58a3aae6ea..825b665245b 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -1223,11 +1223,12 @@ static int pxafb_smart_thread(void *arg) struct pxafb_info *fbi = arg; struct pxafb_mach_info *inf = fbi->dev->platform_data; - if (!fbi || !inf->smart_update) { + if (!inf->smart_update) { pr_err("%s: not properly initialized, thread terminated\n", __func__); return -EINVAL; } + inf = fbi->dev->platform_data; pr_debug("%s(): task starting\n", __func__); @@ -1667,7 +1668,7 @@ static int pxafb_resume(struct device *dev) return 0; } -static struct dev_pm_ops pxafb_pm_ops = { +static const struct dev_pm_ops pxafb_pm_ops = { .suspend = pxafb_suspend, .resume = pxafb_resume, }; diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index adf9632c6b1..53cb722c45a 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -211,21 +211,23 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var, /** * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock. - * @id: window id. * @sfb: The hardware state. * @pixclock: The pixel clock wanted, in picoseconds. * * Given the specified pixel clock, work out the necessary divider to get * close to the output frequency. */ -static int s3c_fb_calc_pixclk(unsigned char id, struct s3c_fb *sfb, unsigned int pixclk) +static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk) { - struct s3c_fb_pd_win *win = sfb->pdata->win[id]; unsigned long clk = clk_get_rate(sfb->bus_clk); + unsigned long long tmp; unsigned int result; - pixclk *= win->win_mode.refresh; - result = clk / pixclk; + tmp = (unsigned long long)clk; + tmp *= pixclk; + + do_div(tmp, 1000000000UL); + result = (unsigned int)tmp / 1000; dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n", pixclk, clk, result, clk / result); @@ -301,7 +303,7 @@ static int s3c_fb_set_par(struct fb_info *info) /* use window 0 as the basis for the lcd output timings */ if (win_no == 0) { - clkdiv = s3c_fb_calc_pixclk(win_no, sfb, var->pixclock); + clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock); data = sfb->pdata->vidcon0; data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR); diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index b4b5de930cf..a69830d26f7 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -281,6 +281,7 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info, struct list_head *pagelist) { struct sh_mobile_lcdc_chan *ch = info->par; + struct sh_mobile_lcdc_board_cfg *bcfg = &ch->cfg.board_cfg; /* enable clocks before accessing hardware */ sh_mobile_lcdc_clk_on(ch->lcdc); @@ -305,10 +306,17 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info, /* trigger panel update */ dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); + if (bcfg->start_transfer) + bcfg->start_transfer(bcfg->board_data, ch, + &sh_mobile_lcdc_sys_bus_ops); lcdc_write_chan(ch, LDSM2R, 1); dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); - } else + } else { + if (bcfg->start_transfer) + bcfg->start_transfer(bcfg->board_data, ch, + &sh_mobile_lcdc_sys_bus_ops); lcdc_write_chan(ch, LDSM2R, 1); + } } static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info) @@ -890,7 +898,7 @@ static int sh_mobile_lcdc_runtime_resume(struct device *dev) return 0; } -static struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = { +static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = { .suspend = sh_mobile_lcdc_suspend, .resume = sh_mobile_lcdc_resume, .runtime_suspend = sh_mobile_lcdc_runtime_suspend, diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index a4e05e4d750..9d2b6bc4903 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -2115,7 +2115,7 @@ sisfb_detect_VB_connect(struct sis_video_info *ivideo) if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) && (!((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_CHRONTEL))) ) { - if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) { + if(ivideo->sisfb_tvstd & (TV_PALM | TV_PALN | TV_NTSCJ)) { ivideo->sisfb_tvstd = -1; printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n"); } diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index 924d7946278..35370d0ecf0 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -29,8 +29,8 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/console.h> +#include <linux/io.h> -#include <asm/io.h> #include <asm/uaccess.h> #include <asm/div64.h> @@ -66,6 +66,7 @@ struct sm501fb_info { struct fb_info *fb[2]; /* fb info for both heads */ struct resource *fbmem_res; /* framebuffer resource */ struct resource *regs_res; /* registers resource */ + struct resource *regs2d_res; /* 2d registers resource */ struct sm501_platdata_fb *pdata; /* our platform data */ unsigned long pm_crt_ctrl; /* pm: crt ctrl save */ @@ -73,6 +74,7 @@ struct sm501fb_info { int irq; int swap_endian; /* set to swap rgb=>bgr */ void __iomem *regs; /* remapped registers */ + void __iomem *regs2d; /* 2d remapped registers */ void __iomem *fbmem; /* remapped framebuffer */ size_t fbmem_len; /* length of remapped region */ }; @@ -123,9 +125,9 @@ static inline void sm501fb_sync_regs(struct sm501fb_info *info) * This is an attempt to lay out memory for the two framebuffers and * everything else * - * |fbmem_res->start fbmem_res->end| - * | | - * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K | + * |fbmem_res->start fbmem_res->end| + * | | + * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K | * |-> fb[0].fix.smem_len <-| spare |-> fb[1].fix.smem_len <-|-> cursors <-| * * The "spare" space is for the 2d engine data @@ -1246,7 +1248,173 @@ static ssize_t sm501fb_debug_show_pnl(struct device *dev, static DEVICE_ATTR(fbregs_pnl, 0444, sm501fb_debug_show_pnl, NULL); -/* framebuffer ops */ +/* acceleration operations */ +static int sm501fb_sync(struct fb_info *info) +{ + int count = 1000000; + struct sm501fb_par *par = info->par; + struct sm501fb_info *fbi = par->info; + + /* wait for the 2d engine to be ready */ + while ((count > 0) && + (readl(fbi->regs + SM501_SYSTEM_CONTROL) & + SM501_SYSCTRL_2D_ENGINE_STATUS) != 0) + count--; + + if (count <= 0) { + dev_err(info->dev, "Timeout waiting for 2d engine sync\n"); + return 1; + } + return 0; +} + +static void sm501fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + struct sm501fb_par *par = info->par; + struct sm501fb_info *fbi = par->info; + int width = area->width; + int height = area->height; + int sx = area->sx; + int sy = area->sy; + int dx = area->dx; + int dy = area->dy; + unsigned long rtl = 0; + + /* source clip */ + if ((sx >= info->var.xres_virtual) || + (sy >= info->var.yres_virtual)) + /* source Area not within virtual screen, skipping */ + return; + if ((sx + width) >= info->var.xres_virtual) + width = info->var.xres_virtual - sx - 1; + if ((sy + height) >= info->var.yres_virtual) + height = info->var.yres_virtual - sy - 1; + + /* dest clip */ + if ((dx >= info->var.xres_virtual) || + (dy >= info->var.yres_virtual)) + /* Destination Area not within virtual screen, skipping */ + return; + if ((dx + width) >= info->var.xres_virtual) + width = info->var.xres_virtual - dx - 1; + if ((dy + height) >= info->var.yres_virtual) + height = info->var.yres_virtual - dy - 1; + + if ((sx < dx) || (sy < dy)) { + rtl = 1 << 27; + sx += width - 1; + dx += width - 1; + sy += height - 1; + dy += height - 1; + } + + if (sm501fb_sync(info)) + return; + + /* set the base addresses */ + writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE); + writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_DESTINATION_BASE); + + /* set the window width */ + writel((info->var.xres << 16) | info->var.xres, + fbi->regs2d + SM501_2D_WINDOW_WIDTH); + + /* set window stride */ + writel((info->var.xres_virtual << 16) | info->var.xres_virtual, + fbi->regs2d + SM501_2D_PITCH); + + /* set data format */ + switch (info->var.bits_per_pixel) { + case 8: + writel(0, fbi->regs2d + SM501_2D_STRETCH); + break; + case 16: + writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH); + break; + case 32: + writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH); + break; + } + + /* 2d compare mask */ + writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK); + + /* 2d mask */ + writel(0xffffffff, fbi->regs2d + SM501_2D_MASK); + + /* source and destination x y */ + writel((sx << 16) | sy, fbi->regs2d + SM501_2D_SOURCE); + writel((dx << 16) | dy, fbi->regs2d + SM501_2D_DESTINATION); + + /* w/h */ + writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION); + + /* do area move */ + writel(0x800000cc | rtl, fbi->regs2d + SM501_2D_CONTROL); +} + +static void sm501fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct sm501fb_par *par = info->par; + struct sm501fb_info *fbi = par->info; + int width = rect->width, height = rect->height; + + if ((rect->dx >= info->var.xres_virtual) || + (rect->dy >= info->var.yres_virtual)) + /* Rectangle not within virtual screen, skipping */ + return; + if ((rect->dx + width) >= info->var.xres_virtual) + width = info->var.xres_virtual - rect->dx - 1; + if ((rect->dy + height) >= info->var.yres_virtual) + height = info->var.yres_virtual - rect->dy - 1; + + if (sm501fb_sync(info)) + return; + + /* set the base addresses */ + writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE); + writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_DESTINATION_BASE); + + /* set the window width */ + writel((info->var.xres << 16) | info->var.xres, + fbi->regs2d + SM501_2D_WINDOW_WIDTH); + + /* set window stride */ + writel((info->var.xres_virtual << 16) | info->var.xres_virtual, + fbi->regs2d + SM501_2D_PITCH); + + /* set data format */ + switch (info->var.bits_per_pixel) { + case 8: + writel(0, fbi->regs2d + SM501_2D_STRETCH); + break; + case 16: + writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH); + break; + case 32: + writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH); + break; + } + + /* 2d compare mask */ + writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK); + + /* 2d mask */ + writel(0xffffffff, fbi->regs2d + SM501_2D_MASK); + + /* colour */ + writel(rect->color, fbi->regs2d + SM501_2D_FOREGROUND); + + /* x y */ + writel((rect->dx << 16) | rect->dy, fbi->regs2d + SM501_2D_DESTINATION); + + /* w/h */ + writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION); + + /* do rectangle fill */ + writel(0x800100cc, fbi->regs2d + SM501_2D_CONTROL); +} + static struct fb_ops sm501fb_ops_crt = { .owner = THIS_MODULE, @@ -1256,9 +1424,10 @@ static struct fb_ops sm501fb_ops_crt = { .fb_setcolreg = sm501fb_setcolreg, .fb_pan_display = sm501fb_pan_crt, .fb_cursor = sm501fb_cursor, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, + .fb_fillrect = sm501fb_fillrect, + .fb_copyarea = sm501fb_copyarea, .fb_imageblit = cfb_imageblit, + .fb_sync = sm501fb_sync, }; static struct fb_ops sm501fb_ops_pnl = { @@ -1269,9 +1438,10 @@ static struct fb_ops sm501fb_ops_pnl = { .fb_blank = sm501fb_blank_pnl, .fb_setcolreg = sm501fb_setcolreg, .fb_cursor = sm501fb_cursor, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, + .fb_fillrect = sm501fb_fillrect, + .fb_copyarea = sm501fb_copyarea, .fb_imageblit = cfb_imageblit, + .fb_sync = sm501fb_sync, }; /* sm501_init_cursor @@ -1329,7 +1499,8 @@ static int sm501fb_start(struct sm501fb_info *info, dev_warn(dev, "no irq for device\n"); } - /* allocate, reserve and remap resources for registers */ + /* allocate, reserve and remap resources for display + * controller registers */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(dev, "no resource definition for registers\n"); @@ -1338,7 +1509,7 @@ static int sm501fb_start(struct sm501fb_info *info, } info->regs_res = request_mem_region(res->start, - res->end - res->start, + resource_size(res), pdev->name); if (info->regs_res == NULL) { @@ -1347,37 +1518,63 @@ static int sm501fb_start(struct sm501fb_info *info, goto err_release; } - info->regs = ioremap(res->start, (res->end - res->start)+1); + info->regs = ioremap(res->start, resource_size(res)); if (info->regs == NULL) { dev_err(dev, "cannot remap registers\n"); ret = -ENXIO; goto err_regs_res; } + /* allocate, reserve and remap resources for 2d + * controller registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res == NULL) { + dev_err(dev, "no resource definition for 2d registers\n"); + ret = -ENOENT; + goto err_regs_map; + } + + info->regs2d_res = request_mem_region(res->start, + resource_size(res), + pdev->name); + + if (info->regs2d_res == NULL) { + dev_err(dev, "cannot claim registers\n"); + ret = -ENXIO; + goto err_regs_map; + } + + info->regs2d = ioremap(res->start, resource_size(res)); + if (info->regs2d == NULL) { + dev_err(dev, "cannot remap registers\n"); + ret = -ENXIO; + goto err_regs2d_res; + } + /* allocate, reserve resources for framebuffer */ res = platform_get_resource(pdev, IORESOURCE_MEM, 2); if (res == NULL) { dev_err(dev, "no memory resource defined\n"); ret = -ENXIO; - goto err_regs_map; + goto err_regs2d_map; } info->fbmem_res = request_mem_region(res->start, - (res->end - res->start)+1, + resource_size(res), pdev->name); if (info->fbmem_res == NULL) { dev_err(dev, "cannot claim framebuffer\n"); ret = -ENXIO; - goto err_regs_map; + goto err_regs2d_map; } - info->fbmem = ioremap(res->start, (res->end - res->start)+1); + info->fbmem = ioremap(res->start, resource_size(res)); if (info->fbmem == NULL) { dev_err(dev, "cannot remap framebuffer\n"); goto err_mem_res; } - info->fbmem_len = (res->end - res->start)+1; + info->fbmem_len = resource_size(res); /* clear framebuffer memory - avoids garbage data on unused fb */ memset(info->fbmem, 0, info->fbmem_len); @@ -1389,8 +1586,10 @@ static int sm501fb_start(struct sm501fb_info *info, /* enable display controller */ sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1); - /* setup cursors */ + /* enable 2d controller */ + sm501_unit_power(dev->parent, SM501_GATE_2D_ENGINE, 1); + /* setup cursors */ sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR); sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR); @@ -1400,6 +1599,13 @@ static int sm501fb_start(struct sm501fb_info *info, release_resource(info->fbmem_res); kfree(info->fbmem_res); + err_regs2d_map: + iounmap(info->regs2d); + + err_regs2d_res: + release_resource(info->regs2d_res); + kfree(info->regs2d_res); + err_regs_map: iounmap(info->regs); @@ -1420,6 +1626,10 @@ static void sm501fb_stop(struct sm501fb_info *info) release_resource(info->fbmem_res); kfree(info->fbmem_res); + iounmap(info->regs2d); + release_resource(info->regs2d_res); + kfree(info->regs2d_res); + iounmap(info->regs); release_resource(info->regs_res); kfree(info->regs_res); @@ -1486,7 +1696,8 @@ static int sm501fb_init_fb(struct fb_info *fb, par->ops.fb_cursor = NULL; fb->fbops = &par->ops; - fb->flags = FBINFO_FLAG_DEFAULT | + fb->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST | + FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; /* fixed data */ diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c index 9d4f3a49ba4..d5077dfa9e0 100644 --- a/drivers/video/via/accel.c +++ b/drivers/video/via/accel.c @@ -137,7 +137,7 @@ static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height, tmp, dst_pitch); return -EINVAL; } - tmp = (tmp >> 3) | (dst_pitch << (16 - 3)); + tmp = VIA_PITCH_ENABLE | (tmp >> 3) | (dst_pitch << (16 - 3)); writel(tmp, engine + 0x38); if (op == VIA_BITBLT_FILL) @@ -352,6 +352,9 @@ int viafb_init_engine(struct fb_info *info) viapar->shared->vq_vram_addr = viapar->fbmem_free; viapar->fbmem_used += VQ_SIZE; + /* Init 2D engine reg to reset 2D engine */ + writel(0x0, engine + VIA_REG_KEYCONTROL); + /* Init AGP and VQ regs */ switch (chip_name) { case UNICHROME_K8M890: diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c index e3e597f937a..09353e2b92f 100644 --- a/drivers/video/via/lcd.c +++ b/drivers/video/via/lcd.c @@ -1134,45 +1134,33 @@ static void integrated_lvds_enable(struct lvds_setting_information *plvds_setting_info, struct lvds_chip_information *plvds_chip_info) { - bool turn_on_first_powersequence = false; - bool turn_on_second_powersequence = false; - DEBUG_MSG(KERN_INFO "integrated_lvds_enable, out_interface:%d\n", plvds_chip_info->output_interface); if (plvds_setting_info->lcd_mode == LCD_SPWG) viafb_write_reg_mask(CRD2, VIACR, 0x00, BIT0 + BIT1); - else + else viafb_write_reg_mask(CRD2, VIACR, 0x03, BIT0 + BIT1); - if (INTERFACE_LVDS0LVDS1 == plvds_chip_info->output_interface) - turn_on_first_powersequence = true; - if (INTERFACE_LVDS0 == plvds_chip_info->output_interface) - turn_on_first_powersequence = true; - if (INTERFACE_LVDS1 == plvds_chip_info->output_interface) - turn_on_second_powersequence = true; - - if (turn_on_second_powersequence) { - /* Use second power sequence control: */ - - /* Use hardware control power sequence. */ - viafb_write_reg_mask(CRD3, VIACR, 0, BIT0); - - /* Turn on back light. */ - viafb_write_reg_mask(CRD3, VIACR, 0, BIT6 + BIT7); - /* Turn on hardware power sequence. */ - viafb_write_reg_mask(CRD4, VIACR, 0x02, BIT1); - } - if (turn_on_first_powersequence) { + switch (plvds_chip_info->output_interface) { + case INTERFACE_LVDS0LVDS1: + case INTERFACE_LVDS0: /* Use first power sequence control: */ - /* Use hardware control power sequence. */ viafb_write_reg_mask(CR91, VIACR, 0, BIT0); - /* Turn on back light. */ viafb_write_reg_mask(CR91, VIACR, 0, BIT6 + BIT7); - /* Turn on hardware power sequence. */ viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3); + break; + case INTERFACE_LVDS1: + /* Use second power sequence control: */ + /* Use hardware control power sequence. */ + viafb_write_reg_mask(CRD3, VIACR, 0, BIT0); + /* Turn on back light. */ + viafb_write_reg_mask(CRD3, VIACR, 0, BIT6 + BIT7); + /* Turn on hardware power sequence. */ + viafb_write_reg_mask(CRD4, VIACR, 0x02, BIT1); + break; } /* Turn DFP High/Low pad on. */ diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 56ec696e8af..3028e7ddc3b 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -177,16 +177,15 @@ static int viafb_set_par(struct fb_info *info) } if (vmode_index != VIA_RES_INVALID) { - viafb_setmode(vmode_index, info->var.xres, info->var.yres, - info->var.bits_per_pixel, vmode_index1, - viafb_second_xres, viafb_second_yres, viafb_bpp1); - viafb_update_fix(info); viafb_bpp = info->var.bits_per_pixel; if (info->var.accel_flags & FB_ACCELF_TEXT) info->flags &= ~FBINFO_HWACCEL_DISABLED; else info->flags |= FBINFO_HWACCEL_DISABLED; + viafb_setmode(vmode_index, info->var.xres, info->var.yres, + info->var.bits_per_pixel, vmode_index1, + viafb_second_xres, viafb_second_yres, viafb_bpp1); } return 0; @@ -680,7 +679,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg) if (!viafb_gamma_table) return -ENOMEM; if (copy_from_user(viafb_gamma_table, argp, - sizeof(viafb_gamma_table))) { + 256 * sizeof(u32))) { kfree(viafb_gamma_table); return -EFAULT; } @@ -694,7 +693,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg) return -ENOMEM; viafb_get_gamma_table(viafb_gamma_table); if (copy_to_user(argp, viafb_gamma_table, - sizeof(viafb_gamma_table))) { + 256 * sizeof(u32))) { kfree(viafb_gamma_table); return -EFAULT; } @@ -872,7 +871,9 @@ static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor) if (info->flags & FBINFO_HWACCEL_DISABLED || info != viafbinfo) return -ENODEV; - if (chip_name == UNICHROME_CLE266 && viapar->iga_path == IGA2) + /* LCD ouput does not support hw cursors (at least on VN896) */ + if ((chip_name == UNICHROME_CLE266 && viapar->iga_path == IGA2) || + viafb_LCD_ON) return -ENODEV; viafb_show_hw_cursor(info, HW_Cursor_OFF); @@ -1797,7 +1798,7 @@ static const struct file_operations viafb_vt1636_proc_fops = { static void viafb_init_proc(struct proc_dir_entry **viafb_entry) { *viafb_entry = proc_mkdir("viafb", NULL); - if (viafb_entry) { + if (*viafb_entry) { proc_create("dvp0", 0, *viafb_entry, &viafb_dvp0_proc_fops); proc_create("dvp1", 0, *viafb_entry, &viafb_dvp1_proc_fops); proc_create("dfph", 0, *viafb_entry, &viafb_dfph_proc_fops); |