diff options
Diffstat (limited to 'drivers/video')
77 files changed, 1728 insertions, 5103 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 22262a3a0e2d..6c793bc683d9 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -27,12 +27,6 @@ config VGASTATE tristate default n -config VIDEO_OUTPUT_CONTROL - tristate "Lowlevel video output switch controls" - help - This framework adds support for low-level control of the video - output switch. - config VIDEOMODE_HELPERS bool @@ -364,7 +358,7 @@ config FB_SA1100 config FB_IMX tristate "Freescale i.MX1/21/25/27 LCD support" - depends on FB && IMX_HAVE_PLATFORM_IMX_FB + depends on FB && ARCH_MXC select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -802,18 +796,9 @@ config FB_HGA As this card technology is at least 25 years old, most people will answer N here. -config FB_SGIVW - tristate "SGI Visual Workstation framebuffer support" - depends on FB && X86_VISWS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - SGI Visual Workstation support for framebuffer graphics. - config FB_GBE bool "SGI Graphics Backend frame buffer support" - depends on (FB = y) && (SGI_IP32 || X86_VISWS) + depends on (FB = y) && SGI_IP32 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -982,7 +967,7 @@ config FB_PVR2 config FB_OPENCORES tristate "OpenCores VGA/LCD core 2.0 framebuffer support" - depends on FB + depends on FB && HAS_DMA select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT diff --git a/drivers/video/Makefile b/drivers/video/Makefile index ae17ddf49a00..1be26fe10592 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -75,7 +75,6 @@ obj-$(CONFIG_FB_CG14) += cg14.o sbuslib.o obj-$(CONFIG_FB_P9100) += p9100.o sbuslib.o obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o -obj-$(CONFIG_FB_SGIVW) += sgivwfb.o obj-$(CONFIG_FB_ACORN) += acornfb.o obj-$(CONFIG_FB_ATARI) += atafb.o c2p_iplan2.o atafb_mfb.o \ atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o @@ -172,8 +171,6 @@ obj-$(CONFIG_FB_SIMPLE) += simplefb.o # the test framebuffer is last obj-$(CONFIG_FB_VIRTUAL) += vfb.o -#video output switch sysfs driver -obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o ifeq ($(CONFIG_OF),y) obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index cd961622f9c1..e683b6ef9594 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -1190,12 +1190,12 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) if (!sinfo->config) goto free_info; - strcpy(info->fix.id, sinfo->pdev->name); info->flags = ATMEL_LCDFB_FBINFO_DEFAULT; info->pseudo_palette = sinfo->pseudo_palette; info->fbops = &atmel_lcdfb_ops; info->fix = atmel_lcdfb_fix; + strcpy(info->fix.id, sinfo->pdev->name); /* Enable LCDC Clocks */ sinfo->bus_clk = clk_get(dev, "hclk"); @@ -1298,6 +1298,12 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) goto unregister_irqs; } + ret = atmel_lcdfb_set_par(info); + if (ret < 0) { + dev_err(dev, "set par failed: %d\n", ret); + goto unregister_irqs; + } + dev_set_drvdata(dev, info); /* diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 28fafbf864a5..c3d0074a32db 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -862,8 +862,8 @@ static int aty_var_to_crtc(const struct fb_info *info, h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; - if ((xres > 1600) || (yres > 1200)) { - FAIL("MACH64 chips are designed for max 1600x1200\n" + if ((xres > 1920) || (yres > 1200)) { + FAIL("MACH64 chips are designed for max 1920x1200\n" "select another resolution."); } h_sync_strt = h_disp + var->right_margin; @@ -2653,7 +2653,8 @@ static int aty_init(struct fb_info *info) FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA | - FBINFO_HWACCEL_YPAN; + FBINFO_HWACCEL_YPAN | + FBINFO_READS_FAST; #ifdef CONFIG_PMAC_BACKLIGHT if (M64_HAS(G3_PB_1_1) && of_machine_is_compatible("PowerBook1,1")) { diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c index e45833ce975b..182bd680141f 100644 --- a/drivers/video/aty/mach64_accel.c +++ b/drivers/video/aty/mach64_accel.c @@ -4,6 +4,7 @@ */ #include <linux/delay.h> +#include <asm/unaligned.h> #include <linux/fb.h> #include <video/mach64.h> #include "atyfb.h" @@ -419,7 +420,7 @@ void atyfb_imageblit(struct fb_info *info, const struct fb_image *image) u32 *pbitmap, dwords = (src_bytes + 3) / 4; for (pbitmap = (u32*)(image->data); dwords; dwords--, pbitmap++) { wait_for_fifo(1, par); - aty_st_le32(HOST_DATA0, le32_to_cpup(pbitmap), par); + aty_st_le32(HOST_DATA0, get_unaligned_le32(pbitmap), par); } } diff --git a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c index 95ec042ddbf8..0fe02e22d9a4 100644 --- a/drivers/video/aty/mach64_cursor.c +++ b/drivers/video/aty/mach64_cursor.c @@ -5,6 +5,7 @@ #include <linux/fb.h> #include <linux/init.h> #include <linux/string.h> +#include "../fb_draw.h" #include <asm/io.h> @@ -157,24 +158,33 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { + u16 l = 0xaaaa; b = *src++; m = *msk++; switch (cursor->rop) { case ROP_XOR: // Upper 4 bits of mask data - fb_writeb(cursor_bits_lookup[(b ^ m) >> 4], dst++); + l = cursor_bits_lookup[(b ^ m) >> 4] | // Lower 4 bits of mask - fb_writeb(cursor_bits_lookup[(b ^ m) & 0x0f], - dst++); + (cursor_bits_lookup[(b ^ m) & 0x0f] << 8); break; case ROP_COPY: // Upper 4 bits of mask data - fb_writeb(cursor_bits_lookup[(b & m) >> 4], dst++); + l = cursor_bits_lookup[(b & m) >> 4] | // Lower 4 bits of mask - fb_writeb(cursor_bits_lookup[(b & m) & 0x0f], - dst++); + (cursor_bits_lookup[(b & m) & 0x0f] << 8); break; } + /* + * If cursor size is not a multiple of 8 characters + * we must pad it with transparent pattern (0xaaaa). + */ + if ((j + 1) * 8 > cursor->image.width) { + l = comp(l, 0xaaaa, + (1 << ((cursor->image.width & 7) * 2)) - 1); + } + fb_writeb(l & 0xff, dst++); + fb_writeb(l >> 8, dst++); } dst += offset; } diff --git a/drivers/video/backlight/aat2870_bl.c b/drivers/video/backlight/aat2870_bl.c index ee0c0a982e4e..ec5350f2c28a 100644 --- a/drivers/video/backlight/aat2870_bl.c +++ b/drivers/video/backlight/aat2870_bl.c @@ -149,8 +149,6 @@ static int aat2870_bl_probe(struct platform_device *pdev) sizeof(struct aat2870_bl_driver_data), GFP_KERNEL); if (!aat2870_bl) { - dev_err(&pdev->dev, - "Failed to allocate memory for aat2870 backlight\n"); ret = -ENOMEM; goto out; } diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 9d656717d0f7..be8d83deca7d 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -224,10 +224,8 @@ static int adp8860_led_probe(struct i2c_client *client) led = devm_kzalloc(&client->dev, sizeof(*led) * pdata->num_leds, GFP_KERNEL); - if (led == NULL) { - dev_err(&client->dev, "failed to alloc memory\n"); + if (led == NULL) return -ENOMEM; - } ret = adp8860_write(client, ADP8860_ISCFR, pdata->led_fade_law); ret = adp8860_write(client, ADP8860_ISCT1, diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c index 63707205326b..251af4d38d86 100644 --- a/drivers/video/backlight/adp8870_bl.c +++ b/drivers/video/backlight/adp8870_bl.c @@ -246,10 +246,8 @@ static int adp8870_led_probe(struct i2c_client *client) led = devm_kzalloc(&client->dev, pdata->num_leds * sizeof(*led), GFP_KERNEL); - if (led == NULL) { - dev_err(&client->dev, "failed to alloc memory\n"); + if (led == NULL) return -ENOMEM; - } ret = adp8870_write(client, ADP8870_ISCLAW, pdata->led_fade_law); if (ret) diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 5d05555fe841..bd2172c2d650 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -34,13 +34,15 @@ static const char *const backlight_types[] = { defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)) /* This callback gets called when something important happens inside a * framebuffer driver. We're looking if that important event is blanking, - * and if it is, we're switching backlight power as well ... + * and if it is and necessary, we're switching backlight power as well ... */ static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) { struct backlight_device *bd; struct fb_event *evdata = data; + int node = evdata->info->node; + int fb_blank = 0; /* If we aren't interested in this event, skip it immediately ... */ if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK) @@ -51,12 +53,24 @@ static int fb_notifier_callback(struct notifier_block *self, if (bd->ops) if (!bd->ops->check_fb || bd->ops->check_fb(bd, evdata->info)) { - bd->props.fb_blank = *(int *)evdata->data; - if (bd->props.fb_blank == FB_BLANK_UNBLANK) - bd->props.state &= ~BL_CORE_FBBLANK; - else - bd->props.state |= BL_CORE_FBBLANK; - backlight_update_status(bd); + fb_blank = *(int *)evdata->data; + if (fb_blank == FB_BLANK_UNBLANK && + !bd->fb_bl_on[node]) { + bd->fb_bl_on[node] = true; + if (!bd->use_count++) { + bd->props.state &= ~BL_CORE_FBBLANK; + bd->props.fb_blank = FB_BLANK_UNBLANK; + backlight_update_status(bd); + } + } else if (fb_blank != FB_BLANK_UNBLANK && + bd->fb_bl_on[node]) { + bd->fb_bl_on[node] = false; + if (!(--bd->use_count)) { + bd->props.state |= BL_CORE_FBBLANK; + bd->props.fb_blank = fb_blank; + backlight_update_status(bd); + } + } } mutex_unlock(&bd->ops_lock); return 0; @@ -333,7 +347,7 @@ struct backlight_device *backlight_device_register(const char *name, rc = device_register(&new_bd->dev); if (rc) { - kfree(new_bd); + put_device(&new_bd->dev); return ERR_PTR(rc); } diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c index db8db5fa6583..51d18d637e2b 100644 --- a/drivers/video/backlight/corgi_lcd.c +++ b/drivers/video/backlight/corgi_lcd.c @@ -543,10 +543,8 @@ static int corgi_lcd_probe(struct spi_device *spi) } lcd = devm_kzalloc(&spi->dev, sizeof(struct corgi_lcd), GFP_KERNEL); - if (!lcd) { - dev_err(&spi->dev, "failed to allocate memory\n"); + if (!lcd) return -ENOMEM; - } lcd->spi_dev = spi; diff --git a/drivers/video/backlight/gpio_backlight.c b/drivers/video/backlight/gpio_backlight.c index 81fb12770c2a..a2eba12e1cb7 100644 --- a/drivers/video/backlight/gpio_backlight.c +++ b/drivers/video/backlight/gpio_backlight.c @@ -13,6 +13,8 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/of_gpio.h> #include <linux/platform_data/gpio_backlight.h> #include <linux/platform_device.h> #include <linux/slab.h> @@ -23,6 +25,7 @@ struct gpio_backlight { int gpio; int active; + int def_value; }; static int gpio_backlight_update_status(struct backlight_device *bl) @@ -60,6 +63,29 @@ static const struct backlight_ops gpio_backlight_ops = { .check_fb = gpio_backlight_check_fb, }; +static int gpio_backlight_probe_dt(struct platform_device *pdev, + struct gpio_backlight *gbl) +{ + struct device_node *np = pdev->dev.of_node; + enum of_gpio_flags gpio_flags; + + gbl->gpio = of_get_gpio_flags(np, 0, &gpio_flags); + + if (!gpio_is_valid(gbl->gpio)) { + if (gbl->gpio != -EPROBE_DEFER) { + dev_err(&pdev->dev, + "Error: The gpios parameter is missing or invalid.\n"); + } + return gbl->gpio; + } + + gbl->active = (gpio_flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1; + + gbl->def_value = of_property_read_bool(np, "default-on"); + + return 0; +} + static int gpio_backlight_probe(struct platform_device *pdev) { struct gpio_backlight_platform_data *pdata = @@ -67,10 +93,12 @@ static int gpio_backlight_probe(struct platform_device *pdev) struct backlight_properties props; struct backlight_device *bl; struct gpio_backlight *gbl; + struct device_node *np = pdev->dev.of_node; int ret; - if (!pdata) { - dev_err(&pdev->dev, "failed to find platform data\n"); + if (!pdata && !np) { + dev_err(&pdev->dev, + "failed to find platform data or device tree node.\n"); return -ENODEV; } @@ -79,14 +107,22 @@ static int gpio_backlight_probe(struct platform_device *pdev) return -ENOMEM; gbl->dev = &pdev->dev; - gbl->fbdev = pdata->fbdev; - gbl->gpio = pdata->gpio; - gbl->active = pdata->active_low ? 0 : 1; + + if (np) { + ret = gpio_backlight_probe_dt(pdev, gbl); + if (ret) + return ret; + } else { + gbl->fbdev = pdata->fbdev; + gbl->gpio = pdata->gpio; + gbl->active = pdata->active_low ? 0 : 1; + gbl->def_value = pdata->def_value; + } ret = devm_gpio_request_one(gbl->dev, gbl->gpio, GPIOF_DIR_OUT | (gbl->active ? GPIOF_INIT_LOW : GPIOF_INIT_HIGH), - pdata->name); + pdata ? pdata->name : "backlight"); if (ret < 0) { dev_err(&pdev->dev, "unable to request GPIO\n"); return ret; @@ -103,17 +139,25 @@ static int gpio_backlight_probe(struct platform_device *pdev) return PTR_ERR(bl); } - bl->props.brightness = pdata->def_value; + bl->props.brightness = gbl->def_value; backlight_update_status(bl); platform_set_drvdata(pdev, bl); return 0; } +#ifdef CONFIG_OF +static struct of_device_id gpio_backlight_of_match[] = { + { .compatible = "gpio-backlight" }, + { /* sentinel */ } +}; +#endif + static struct platform_driver gpio_backlight_driver = { .driver = { .name = "gpio-backlight", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(gpio_backlight_of_match), }, .probe = gpio_backlight_probe, }; diff --git a/drivers/video/backlight/hx8357.c b/drivers/video/backlight/hx8357.c index 985e854e244b..23f50b92a930 100644 --- a/drivers/video/backlight/hx8357.c +++ b/drivers/video/backlight/hx8357.c @@ -587,10 +587,8 @@ static int hx8357_probe(struct spi_device *spi) int i, ret; lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL); - if (!lcd) { - dev_err(&spi->dev, "Couldn't allocate lcd internal structure!\n"); + if (!lcd) return -ENOMEM; - } ret = spi_setup(spi); if (ret < 0) { diff --git a/drivers/video/backlight/ili922x.c b/drivers/video/backlight/ili922x.c index 73464e4b4c74..ea67fe199e34 100644 --- a/drivers/video/backlight/ili922x.c +++ b/drivers/video/backlight/ili922x.c @@ -482,10 +482,8 @@ static int ili922x_probe(struct spi_device *spi) u16 reg = 0; ili = devm_kzalloc(&spi->dev, sizeof(*ili), GFP_KERNEL); - if (!ili) { - dev_err(&spi->dev, "cannot alloc priv data\n"); + if (!ili) return -ENOMEM; - } ili->spi = spi; spi_set_drvdata(spi, ili); diff --git a/drivers/video/backlight/ili9320.c b/drivers/video/backlight/ili9320.c index e2b8b40a9bd9..2cf39e6d519d 100644 --- a/drivers/video/backlight/ili9320.c +++ b/drivers/video/backlight/ili9320.c @@ -219,10 +219,8 @@ int ili9320_probe_spi(struct spi_device *spi, /* allocate and initialse our state */ ili = devm_kzalloc(&spi->dev, sizeof(struct ili9320), GFP_KERNEL); - if (ili == NULL) { - dev_err(dev, "no memory for device\n"); + if (ili == NULL) return -ENOMEM; - } ili->access.spi.id = ILI9320_SPI_IDCODE | ILI9320_SPI_ID(1); diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index 63e763828e0e..5fa2649c9631 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -181,11 +181,8 @@ static int l4f00242t03_probe(struct spi_device *spi) priv = devm_kzalloc(&spi->dev, sizeof(struct l4f00242t03_priv), GFP_KERNEL); - - if (priv == NULL) { - dev_err(&spi->dev, "No memory for this device.\n"); + if (priv == NULL) return -ENOMEM; - } spi_set_drvdata(spi, priv); spi->bits_per_word = 9; diff --git a/drivers/video/backlight/lm3533_bl.c b/drivers/video/backlight/lm3533_bl.c index 187d1c283c1d..cff1fbe89a1b 100644 --- a/drivers/video/backlight/lm3533_bl.c +++ b/drivers/video/backlight/lm3533_bl.c @@ -296,11 +296,8 @@ static int lm3533_bl_probe(struct platform_device *pdev) } bl = devm_kzalloc(&pdev->dev, sizeof(*bl), GFP_KERNEL); - if (!bl) { - dev_err(&pdev->dev, - "failed to allocate memory for backlight\n"); + if (!bl) return -ENOMEM; - } bl->lm3533 = lm3533; bl->id = pdev->id; diff --git a/drivers/video/backlight/lm3639_bl.c b/drivers/video/backlight/lm3639_bl.c index 6fd60adf922e..5f36808d214f 100644 --- a/drivers/video/backlight/lm3639_bl.c +++ b/drivers/video/backlight/lm3639_bl.c @@ -349,8 +349,9 @@ static int lm3639_probe(struct i2c_client *client, props.brightness = pdata->init_brt_led; props.max_brightness = pdata->max_brt_led; pchip->bled = - backlight_device_register("lm3639_bled", pchip->dev, pchip, - &lm3639_bled_ops, &props); + devm_backlight_device_register(pchip->dev, "lm3639_bled", + pchip->dev, pchip, &lm3639_bled_ops, + &props); if (IS_ERR(pchip->bled)) { dev_err(&client->dev, "fail : backlight register\n"); ret = PTR_ERR(pchip->bled); @@ -360,7 +361,7 @@ static int lm3639_probe(struct i2c_client *client, ret = device_create_file(&(pchip->bled->dev), &dev_attr_bled_mode); if (ret < 0) { dev_err(&client->dev, "failed : add sysfs entries\n"); - goto err_bled_mode; + goto err_out; } /* flash */ @@ -391,8 +392,6 @@ err_torch: led_classdev_unregister(&pchip->cdev_flash); err_flash: device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode); -err_bled_mode: - backlight_device_unregister(pchip->bled); err_out: return ret; } @@ -407,10 +406,8 @@ static int lm3639_remove(struct i2c_client *client) led_classdev_unregister(&pchip->cdev_torch); if (&pchip->cdev_flash) led_classdev_unregister(&pchip->cdev_flash); - if (pchip->bled) { + if (pchip->bled) device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode); - backlight_device_unregister(pchip->bled); - } return 0; } @@ -432,6 +429,6 @@ static struct i2c_driver lm3639_i2c_driver = { module_i2c_driver(lm3639_i2c_driver); MODULE_DESCRIPTION("Texas Instruments Backlight+Flash LED driver for LM3639"); -MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>"); -MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>"); +MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>"); +MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/video/backlight/lms283gf05.c b/drivers/video/backlight/lms283gf05.c index de8832504f68..14590c54aedf 100644 --- a/drivers/video/backlight/lms283gf05.c +++ b/drivers/video/backlight/lms283gf05.c @@ -168,10 +168,8 @@ static int lms283gf05_probe(struct spi_device *spi) st = devm_kzalloc(&spi->dev, sizeof(struct lms283gf05_state), GFP_KERNEL); - if (st == NULL) { - dev_err(&spi->dev, "No memory for device state\n"); + if (st == NULL) return -ENOMEM; - } ld = devm_lcd_device_register(&spi->dev, "lms283gf05", &spi->dev, st, &lms_ops); diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c index d01884d4f1bf..c3d2e209fc8f 100644 --- a/drivers/video/backlight/platform_lcd.c +++ b/drivers/video/backlight/platform_lcd.c @@ -94,10 +94,8 @@ static int platform_lcd_probe(struct platform_device *pdev) plcd = devm_kzalloc(&pdev->dev, sizeof(struct platform_lcd), GFP_KERNEL); - if (!plcd) { - dev_err(dev, "no memory for state\n"); + if (!plcd) return -ENOMEM; - } plcd->us = dev; plcd->pdata = pdata; diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c index cbba37e6836e..595dcf561020 100644 --- a/drivers/video/backlight/tps65217_bl.c +++ b/drivers/video/backlight/tps65217_bl.c @@ -200,7 +200,6 @@ tps65217_bl_parse_dt(struct platform_device *pdev) pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) { - dev_err(&pdev->dev, "failed to allocate platform data\n"); err = ERR_PTR(-ENOMEM); goto err; } @@ -296,10 +295,8 @@ static int tps65217_bl_probe(struct platform_device *pdev) tps65217_bl = devm_kzalloc(&pdev->dev, sizeof(*tps65217_bl), GFP_KERNEL); - if (tps65217_bl == NULL) { - dev_err(&pdev->dev, "allocation of struct tps65217_bl failed\n"); + if (tps65217_bl == NULL) return -ENOMEM; - } tps65217_bl->tps = tps; tps65217_bl->dev = &pdev->dev; diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c index bb5a96b1645d..bcb57235fcc7 100644 --- a/drivers/video/cfbcopyarea.c +++ b/drivers/video/cfbcopyarea.c @@ -43,13 +43,22 @@ */ static void -bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, - const unsigned long __iomem *src, int src_idx, int bits, +bitcpy(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx, + const unsigned long __iomem *src, unsigned src_idx, int bits, unsigned n, u32 bswapmask) { unsigned long first, last; int const shift = dst_idx-src_idx; - int left, right; + +#if 0 + /* + * If you suspect bug in this function, compare it with this simple + * memmove implementation. + */ + fb_memmove((char *)dst + ((dst_idx & (bits - 1))) / 8, + (char *)src + ((src_idx & (bits - 1))) / 8, n / 8); + return; +#endif first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); @@ -98,9 +107,8 @@ bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, unsigned long d0, d1; int m; - right = shift & (bits - 1); - left = -shift & (bits - 1); - bswapmask &= shift; + int const left = shift & (bits - 1); + int const right = -shift & (bits - 1); if (dst_idx+n <= bits) { // Single destination word @@ -110,15 +118,15 @@ bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, d0 = fb_rev_pixels_in_long(d0, bswapmask); if (shift > 0) { // Single source word - d0 >>= right; + d0 <<= left; } else if (src_idx+n <= bits) { // Single source word - d0 <<= left; + d0 >>= right; } else { // 2 source words d1 = FB_READL(src + 1); d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0<<left | d1>>right; + d0 = d0 >> right | d1 << left; } d0 = fb_rev_pixels_in_long(d0, bswapmask); FB_WRITEL(comp(d0, FB_READL(dst), first), dst); @@ -135,60 +143,59 @@ bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, if (shift > 0) { // Single source word d1 = d0; - d0 >>= right; - dst++; + d0 <<= left; n -= bits - dst_idx; } else { // 2 source words d1 = FB_READL(src++); d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0<<left | d1>>right; - dst++; + d0 = d0 >> right | d1 << left; n -= bits - dst_idx; } d0 = fb_rev_pixels_in_long(d0, bswapmask); FB_WRITEL(comp(d0, FB_READL(dst), first), dst); d0 = d1; + dst++; // Main chunk m = n % bits; n /= bits; while ((n >= 4) && !bswapmask) { d1 = FB_READL(src++); - FB_WRITEL(d0 << left | d1 >> right, dst++); + FB_WRITEL(d0 >> right | d1 << left, dst++); d0 = d1; d1 = FB_READL(src++); - FB_WRITEL(d0 << left | d1 >> right, dst++); + FB_WRITEL(d0 >> right | d1 << left, dst++); d0 = d1; d1 = FB_READL(src++); - FB_WRITEL(d0 << left | d1 >> right, dst++); + FB_WRITEL(d0 >> right | d1 << left, dst++); d0 = d1; d1 = FB_READL(src++); - FB_WRITEL(d0 << left | d1 >> right, dst++); + FB_WRITEL(d0 >> right | d1 << left, dst++); d0 = d1; n -= 4; } while (n--) { d1 = FB_READL(src++); d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0 << left | d1 >> right; + d0 = d0 >> right | d1 << left; d0 = fb_rev_pixels_in_long(d0, bswapmask); FB_WRITEL(d0, dst++); d0 = d1; } // Trailing bits - if (last) { - if (m <= right) { + if (m) { + if (m <= bits - right) { // Single source word - d0 <<= left; + d0 >>= right; } else { // 2 source words d1 = FB_READL(src); d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0<<left | d1>>right; + d0 = d0 >> right | d1 << left; } d0 = fb_rev_pixels_in_long(d0, bswapmask); FB_WRITEL(comp(d0, FB_READL(dst), last), dst); @@ -202,43 +209,46 @@ bitcpy(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, */ static void -bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, - const unsigned long __iomem *src, int src_idx, int bits, +bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx, + const unsigned long __iomem *src, unsigned src_idx, int bits, unsigned n, u32 bswapmask) { unsigned long first, last; int shift; - dst += (n-1)/bits; - src += (n-1)/bits; - if ((n-1) % bits) { - dst_idx += (n-1) % bits; - dst += dst_idx >> (ffs(bits) - 1); - dst_idx &= bits - 1; - src_idx += (n-1) % bits; - src += src_idx >> (ffs(bits) - 1); - src_idx &= bits - 1; - } +#if 0 + /* + * If you suspect bug in this function, compare it with this simple + * memmove implementation. + */ + fb_memmove((char *)dst + ((dst_idx & (bits - 1))) / 8, + (char *)src + ((src_idx & (bits - 1))) / 8, n / 8); + return; +#endif + + dst += (dst_idx + n - 1) / bits; + src += (src_idx + n - 1) / bits; + dst_idx = (dst_idx + n - 1) % bits; + src_idx = (src_idx + n - 1) % bits; shift = dst_idx-src_idx; - first = fb_shifted_pixels_mask_long(p, bits - 1 - dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long(p, bits - 1 - ((dst_idx-n) % bits), - bswapmask); + first = ~fb_shifted_pixels_mask_long(p, (dst_idx + 1) % bits, bswapmask); + last = fb_shifted_pixels_mask_long(p, (bits + dst_idx + 1 - n) % bits, bswapmask); if (!shift) { // Same alignment for source and dest if ((unsigned long)dst_idx+1 >= n) { // Single word - if (last) - first &= last; - FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); + if (first) + last &= first; + FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); } else { // Multiple destination words // Leading bits - if (first != ~0UL) { + if (first) { FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); dst--; src--; @@ -262,7 +272,7 @@ bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, FB_WRITEL(FB_READL(src--), dst--); // Trailing bits - if (last) + if (last != -1UL) FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); } } else { @@ -270,29 +280,28 @@ bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, unsigned long d0, d1; int m; - int const left = -shift & (bits-1); - int const right = shift & (bits-1); - bswapmask &= shift; + int const left = shift & (bits-1); + int const right = -shift & (bits-1); if ((unsigned long)dst_idx+1 >= n) { // Single destination word - if (last) - first &= last; + if (first) + last &= first; d0 = FB_READL(src); if (shift < 0) { // Single source word - d0 <<= left; + d0 >>= right; } else if (1+(unsigned long)src_idx >= n) { // Single source word - d0 >>= right; + d0 <<= left; } else { // 2 source words d1 = FB_READL(src - 1); d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0>>right | d1<<left; + d0 = d0 << left | d1 >> right; } d0 = fb_rev_pixels_in_long(d0, bswapmask); - FB_WRITEL(comp(d0, FB_READL(dst), first), dst); + FB_WRITEL(comp(d0, FB_READL(dst), last), dst); } else { // Multiple destination words /** We must always remember the last value read, because in case @@ -307,12 +316,12 @@ bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, if (shift < 0) { // Single source word d1 = d0; - d0 <<= left; + d0 >>= right; } else { // 2 source words d1 = FB_READL(src--); d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0>>right | d1<<left; + d0 = d0 << left | d1 >> right; } d0 = fb_rev_pixels_in_long(d0, bswapmask); FB_WRITEL(comp(d0, FB_READL(dst), first), dst); @@ -325,39 +334,39 @@ bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, n /= bits; while ((n >= 4) && !bswapmask) { d1 = FB_READL(src--); - FB_WRITEL(d0 >> right | d1 << left, dst--); + FB_WRITEL(d0 << left | d1 >> right, dst--); d0 = d1; d1 = FB_READL(src--); - FB_WRITEL(d0 >> right | d1 << left, dst--); + FB_WRITEL(d0 << left | d1 >> right, dst--); d0 = d1; d1 = FB_READL(src--); - FB_WRITEL(d0 >> right | d1 << left, dst--); + FB_WRITEL(d0 << left | d1 >> right, dst--); d0 = d1; d1 = FB_READL(src--); - FB_WRITEL(d0 >> right | d1 << left, dst--); + FB_WRITEL(d0 << left | d1 >> right, dst--); d0 = d1; n -= 4; } while (n--) { d1 = FB_READL(src--); d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0 >> right | d1 << left; + d0 = d0 << left | d1 >> right; d0 = fb_rev_pixels_in_long(d0, bswapmask); FB_WRITEL(d0, dst--); d0 = d1; } // Trailing bits - if (last) { - if (m <= left) { + if (m) { + if (m <= bits - left) { // Single source word - d0 >>= right; + d0 <<= left; } else { // 2 source words d1 = FB_READL(src); d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0>>right | d1<<left; + d0 = d0 << left | d1 >> right; } d0 = fb_rev_pixels_in_long(d0, bswapmask); FB_WRITEL(comp(d0, FB_READL(dst), last), dst); @@ -371,9 +380,9 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; u32 height = area->height, width = area->width; unsigned long const bits_per_line = p->fix.line_length*8u; - unsigned long __iomem *dst = NULL, *src = NULL; + unsigned long __iomem *base = NULL; int bits = BITS_PER_LONG, bytes = bits >> 3; - int dst_idx = 0, src_idx = 0, rev_copy = 0; + unsigned dst_idx = 0, src_idx = 0, rev_copy = 0; u32 bswapmask = fb_compute_bswapmask(p); if (p->state != FBINFO_STATE_RUNNING) @@ -389,7 +398,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) // split the base of the framebuffer into a long-aligned address and the // index of the first bit - dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1)); + base = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1)); dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1)); // add offset of source and target area dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel; @@ -402,20 +411,14 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) while (height--) { dst_idx -= bits_per_line; src_idx -= bits_per_line; - dst += dst_idx >> (ffs(bits) - 1); - dst_idx &= (bytes - 1); - src += src_idx >> (ffs(bits) - 1); - src_idx &= (bytes - 1); - bitcpy_rev(p, dst, dst_idx, src, src_idx, bits, + bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits, + base + (src_idx / bits), src_idx % bits, bits, width*p->var.bits_per_pixel, bswapmask); } } else { while (height--) { - dst += dst_idx >> (ffs(bits) - 1); - dst_idx &= (bytes - 1); - src += src_idx >> (ffs(bits) - 1); - src_idx &= (bytes - 1); - bitcpy(p, dst, dst_idx, src, src_idx, bits, + bitcpy(p, base + (dst_idx / bits), dst_idx % bits, + base + (src_idx / bits), src_idx % bits, bits, width*p->var.bits_per_pixel, bswapmask); dst_idx += bits_per_line; src_idx += bits_per_line; diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 4e39291ac8b4..f447734b09b4 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -759,7 +759,7 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo, newinfo in an undefined state. Thus, a call to fb_set_par() may be needed for the newinfo. */ - if (newinfo->fbops->fb_set_par) { + if (newinfo && newinfo->fbops->fb_set_par) { ret = newinfo->fbops->fb_set_par(newinfo); if (ret) @@ -3028,8 +3028,31 @@ static int fbcon_fb_unbind(int idx) if (con2fb_map[i] == idx) set_con2fb_map(i, new_idx, 0); } - } else + } else { + struct fb_info *info = registered_fb[idx]; + + /* This is sort of like set_con2fb_map, except it maps + * the consoles to no device and then releases the + * oldinfo to free memory and cancel the cursor blink + * timer. I can imagine this just becoming part of + * set_con2fb_map where new_idx is -1 + */ + for (i = first_fb_vc; i <= last_fb_vc; i++) { + if (con2fb_map[i] == idx) { + con2fb_map[i] = -1; + if (!search_fb_in_map(idx)) { + ret = con2fb_release_oldinfo(vc_cons[i].d, + info, NULL, i, + idx, 0); + if (ret) { + con2fb_map[i] = idx; + return ret; + } + } + } + } ret = fbcon_unbind(); + } return ret; } diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index a1d74dd11988..0c0ba920ea48 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -1546,7 +1546,7 @@ err_pm_runtime_disable: return ret; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static struct lcdc_context { u32 clk_enable; u32 ctrl; @@ -1610,9 +1610,9 @@ static void lcd_context_restore(void) return; } -static int fb_suspend(struct platform_device *dev, pm_message_t state) +static int fb_suspend(struct device *dev) { - struct fb_info *info = platform_get_drvdata(dev); + struct fb_info *info = dev_get_drvdata(dev); struct da8xx_fb_par *par = info->par; console_lock(); @@ -1622,18 +1622,18 @@ static int fb_suspend(struct platform_device *dev, pm_message_t state) fb_set_suspend(info, 1); lcd_disable_raster(DA8XX_FRAME_WAIT); lcd_context_save(); - pm_runtime_put_sync(&dev->dev); + pm_runtime_put_sync(dev); console_unlock(); return 0; } -static int fb_resume(struct platform_device *dev) +static int fb_resume(struct device *dev) { - struct fb_info *info = platform_get_drvdata(dev); + struct fb_info *info = dev_get_drvdata(dev); struct da8xx_fb_par *par = info->par; console_lock(); - pm_runtime_get_sync(&dev->dev); + pm_runtime_get_sync(dev); lcd_context_restore(); if (par->blank == FB_BLANK_UNBLANK) { lcd_enable_raster(); @@ -1647,19 +1647,17 @@ static int fb_resume(struct platform_device *dev) return 0; } -#else -#define fb_suspend NULL -#define fb_resume NULL #endif +static SIMPLE_DEV_PM_OPS(fb_pm_ops, fb_suspend, fb_resume); + static struct platform_driver da8xx_fb_driver = { .probe = fb_probe, .remove = fb_remove, - .suspend = fb_suspend, - .resume = fb_resume, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, + .pm = &fb_pm_ops, }, }; module_platform_driver(da8xx_fb_driver); diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index cd7c0df9f24b..ae9618ff6735 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -73,7 +73,6 @@ static void efifb_destroy(struct fb_info *info) release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); } static struct fb_ops efifb_ops = { @@ -244,6 +243,7 @@ static int efifb_probe(struct platform_device *dev) err = -ENOMEM; goto err_release_mem; } + platform_set_drvdata(dev, info); info->pseudo_palette = info->par; info->par = NULL; @@ -337,12 +337,23 @@ err_release_mem: return err; } +static int efifb_remove(struct platform_device *pdev) +{ + struct fb_info *info = platform_get_drvdata(pdev); + + unregister_framebuffer(info); + framebuffer_release(info); + + return 0; +} + static struct platform_driver efifb_driver = { .driver = { .name = "efi-framebuffer", .owner = THIS_MODULE, }, .probe = efifb_probe, + .remove = efifb_remove, }; module_platform_driver(efifb_driver); diff --git a/drivers/video/exynos/Kconfig b/drivers/video/exynos/Kconfig index 1129d0e9e640..fcf2d48ac6d1 100644 --- a/drivers/video/exynos/Kconfig +++ b/drivers/video/exynos/Kconfig @@ -22,17 +22,11 @@ config EXYNOS_MIPI_DSI config EXYNOS_LCD_S6E8AX0 bool "S6E8AX0 MIPI AMOLED LCD Driver" - depends on (EXYNOS_MIPI_DSI && BACKLIGHT_CLASS_DEVICE && LCD_CLASS_DEVICE) + depends on EXYNOS_MIPI_DSI && BACKLIGHT_CLASS_DEVICE + depends on (LCD_CLASS_DEVICE = y) default n help If you have an S6E8AX0 MIPI AMOLED LCD Panel, say Y to enable its LCD control driver. -config EXYNOS_DP - bool "EXYNOS DP driver support" - depends on OF && ARCH_EXYNOS - default n - help - This enables support for DP device. - endif # EXYNOS_VIDEO diff --git a/drivers/video/exynos/Makefile b/drivers/video/exynos/Makefile index ec7772e452a9..b5b1bd228abb 100644 --- a/drivers/video/exynos/Makefile +++ b/drivers/video/exynos/Makefile @@ -5,4 +5,3 @@ obj-$(CONFIG_EXYNOS_MIPI_DSI) += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \ exynos_mipi_dsi_lowlevel.o obj-$(CONFIG_EXYNOS_LCD_S6E8AX0) += s6e8ax0.o -obj-$(CONFIG_EXYNOS_DP) += exynos_dp_core.o exynos_dp_reg.o diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c deleted file mode 100644 index 5e1a71580051..000000000000 --- a/drivers/video/exynos/exynos_dp_core.c +++ /dev/null @@ -1,1156 +0,0 @@ -/* - * Samsung SoC DP (Display Port) interface driver. - * - * Copyright (C) 2012 Samsung Electronics Co., Ltd. - * Author: Jingoo Han <jg1.han@samsung.com> - * - * 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. - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/err.h> -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/of.h> -#include <linux/phy/phy.h> - -#include "exynos_dp_core.h" - -static int exynos_dp_init_dp(struct exynos_dp_device *dp) -{ - exynos_dp_reset(dp); - - exynos_dp_swreset(dp); - - exynos_dp_init_analog_param(dp); - exynos_dp_init_interrupt(dp); - - /* SW defined function Normal operation */ - exynos_dp_enable_sw_function(dp); - - exynos_dp_config_interrupt(dp); - exynos_dp_init_analog_func(dp); - - exynos_dp_init_hpd(dp); - exynos_dp_init_aux(dp); - - return 0; -} - -static int exynos_dp_detect_hpd(struct exynos_dp_device *dp) -{ - int timeout_loop = 0; - - while (exynos_dp_get_plug_in_status(dp) != 0) { - timeout_loop++; - if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { - dev_err(dp->dev, "failed to get hpd plug status\n"); - return -ETIMEDOUT; - } - usleep_range(10, 11); - } - - return 0; -} - -static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data) -{ - int i; - unsigned char sum = 0; - - for (i = 0; i < EDID_BLOCK_LENGTH; i++) - sum = sum + edid_data[i]; - - return sum; -} - -static int exynos_dp_read_edid(struct exynos_dp_device *dp) -{ - unsigned char edid[EDID_BLOCK_LENGTH * 2]; - unsigned int extend_block = 0; - unsigned char sum; - unsigned char test_vector; - int retval; - - /* - * EDID device address is 0x50. - * However, if necessary, you must have set upper address - * into E-EDID in I2C device, 0x30. - */ - - /* Read Extension Flag, Number of 128-byte EDID extension blocks */ - retval = exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, - EDID_EXTENSION_FLAG, - &extend_block); - if (retval) - return retval; - - if (extend_block > 0) { - dev_dbg(dp->dev, "EDID data includes a single extension!\n"); - - /* Read EDID data */ - retval = exynos_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR, - EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, - &edid[EDID_HEADER_PATTERN]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = exynos_dp_calc_edid_check_sum(edid); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - /* Read additional EDID data */ - retval = exynos_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_BLOCK_LENGTH, - EDID_BLOCK_LENGTH, - &edid[EDID_BLOCK_LENGTH]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TEST_REQUEST, - &test_vector); - if (test_vector & DPCD_TEST_EDID_READ) { - exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TEST_EDID_CHECKSUM, - edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); - exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TEST_RESPONSE, - DPCD_TEST_EDID_CHECKSUM_WRITE); - } - } else { - dev_info(dp->dev, "EDID data does not include any extensions.\n"); - - /* Read EDID data */ - retval = exynos_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, - &edid[EDID_HEADER_PATTERN]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = exynos_dp_calc_edid_check_sum(edid); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } - - exynos_dp_read_byte_from_dpcd(dp, - DPCD_ADDR_TEST_REQUEST, - &test_vector); - if (test_vector & DPCD_TEST_EDID_READ) { - exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TEST_EDID_CHECKSUM, - edid[EDID_CHECKSUM]); - exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TEST_RESPONSE, - DPCD_TEST_EDID_CHECKSUM_WRITE); - } - } - - dev_err(dp->dev, "EDID Read success!\n"); - return 0; -} - -static int exynos_dp_handle_edid(struct exynos_dp_device *dp) -{ - u8 buf[12]; - int i; - int retval; - - /* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */ - retval = exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_DPCD_REV, - 12, buf); - if (retval) - return retval; - - /* Read EDID */ - for (i = 0; i < 3; i++) { - retval = exynos_dp_read_edid(dp); - if (!retval) - break; - } - - return retval; -} - -static void exynos_dp_enable_rx_to_enhanced_mode(struct exynos_dp_device *dp, - bool enable) -{ - u8 data; - - exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data); - - if (enable) - exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, - DPCD_ENHANCED_FRAME_EN | - DPCD_LANE_COUNT_SET(data)); - else - exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, - DPCD_LANE_COUNT_SET(data)); -} - -static int exynos_dp_is_enhanced_mode_available(struct exynos_dp_device *dp) -{ - u8 data; - int retval; - - exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data); - retval = DPCD_ENHANCED_FRAME_CAP(data); - - return retval; -} - -static void exynos_dp_set_enhanced_mode(struct exynos_dp_device *dp) -{ - u8 data; - - data = exynos_dp_is_enhanced_mode_available(dp); - exynos_dp_enable_rx_to_enhanced_mode(dp, data); - exynos_dp_enable_enhanced_mode(dp, data); -} - -static void exynos_dp_training_pattern_dis(struct exynos_dp_device *dp) -{ - exynos_dp_set_training_pattern(dp, DP_NONE); - - exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - DPCD_TRAINING_PATTERN_DISABLED); -} - -static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp, - int pre_emphasis, int lane) -{ - switch (lane) { - case 0: - exynos_dp_set_lane0_pre_emphasis(dp, pre_emphasis); - break; - case 1: - exynos_dp_set_lane1_pre_emphasis(dp, pre_emphasis); - break; - - case 2: - exynos_dp_set_lane2_pre_emphasis(dp, pre_emphasis); - break; - - case 3: - exynos_dp_set_lane3_pre_emphasis(dp, pre_emphasis); - break; - } -} - -static int exynos_dp_link_start(struct exynos_dp_device *dp) -{ - u8 buf[4]; - int lane, lane_count, pll_tries, retval; - - lane_count = dp->link_train.lane_count; - - dp->link_train.lt_state = CLOCK_RECOVERY; - dp->link_train.eq_loop = 0; - - for (lane = 0; lane < lane_count; lane++) - dp->link_train.cr_loop[lane] = 0; - - /* Set link rate and count as you want to establish*/ - exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate); - exynos_dp_set_lane_count(dp, dp->link_train.lane_count); - - /* Setup RX configuration */ - buf[0] = dp->link_train.link_rate; - buf[1] = dp->link_train.lane_count; - retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET, - 2, buf); - if (retval) - return retval; - - /* Set TX pre-emphasis to minimum */ - for (lane = 0; lane < lane_count; lane++) - exynos_dp_set_lane_lane_pre_emphasis(dp, - PRE_EMPHASIS_LEVEL_0, lane); - - /* Wait for PLL lock */ - pll_tries = 0; - while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { - if (pll_tries == DP_TIMEOUT_LOOP_COUNT) { - dev_err(dp->dev, "Wait for PLL lock timed out\n"); - return -ETIMEDOUT; - } - - pll_tries++; - usleep_range(90, 120); - } - - /* Set training pattern 1 */ - exynos_dp_set_training_pattern(dp, TRAINING_PTN1); - - /* Set RX training pattern */ - retval = exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1); - if (retval) - return retval; - - for (lane = 0; lane < lane_count; lane++) - buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 | - DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0; - - retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET, - lane_count, buf); - - return retval; -} - -static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane) -{ - int shift = (lane & 1) * 4; - u8 link_value = link_status[lane>>1]; - - return (link_value >> shift) & 0xf; -} - -static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count) -{ - int lane; - u8 lane_status; - - for (lane = 0; lane < lane_count; lane++) { - lane_status = exynos_dp_get_lane_status(link_status, lane); - if ((lane_status & DPCD_LANE_CR_DONE) == 0) - return -EINVAL; - } - return 0; -} - -static int exynos_dp_channel_eq_ok(u8 link_status[2], u8 link_align, - int lane_count) -{ - int lane; - u8 lane_status; - - if ((link_align & DPCD_INTERLANE_ALIGN_DONE) == 0) - return -EINVAL; - - for (lane = 0; lane < lane_count; lane++) { - lane_status = exynos_dp_get_lane_status(link_status, lane); - lane_status &= DPCD_CHANNEL_EQ_BITS; - if (lane_status != DPCD_CHANNEL_EQ_BITS) - return -EINVAL; - } - - return 0; -} - -static unsigned char exynos_dp_get_adjust_request_voltage(u8 adjust_request[2], - int lane) -{ - int shift = (lane & 1) * 4; - u8 link_value = adjust_request[lane>>1]; - - return (link_value >> shift) & 0x3; -} - -static unsigned char exynos_dp_get_adjust_request_pre_emphasis( - u8 adjust_request[2], - int lane) -{ - int shift = (lane & 1) * 4; - u8 link_value = adjust_request[lane>>1]; - - return ((link_value >> shift) & 0xc) >> 2; -} - -static void exynos_dp_set_lane_link_training(struct exynos_dp_device *dp, - u8 training_lane_set, int lane) -{ - switch (lane) { - case 0: - exynos_dp_set_lane0_link_training(dp, training_lane_set); - break; - case 1: - exynos_dp_set_lane1_link_training(dp, training_lane_set); - break; - - case 2: - exynos_dp_set_lane2_link_training(dp, training_lane_set); - break; - - case 3: - exynos_dp_set_lane3_link_training(dp, training_lane_set); - break; - } -} - -static unsigned int exynos_dp_get_lane_link_training( - struct exynos_dp_device *dp, - int lane) -{ - u32 reg; - - switch (lane) { - case 0: - reg = exynos_dp_get_lane0_link_training(dp); - break; - case 1: - reg = exynos_dp_get_lane1_link_training(dp); - break; - case 2: - reg = exynos_dp_get_lane2_link_training(dp); - break; - case 3: - reg = exynos_dp_get_lane3_link_training(dp); - break; - default: - WARN_ON(1); - return 0; - } - - return reg; -} - -static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp) -{ - exynos_dp_training_pattern_dis(dp); - exynos_dp_set_enhanced_mode(dp); - - dp->link_train.lt_state = FAILED; -} - -static void exynos_dp_get_adjust_training_lane(struct exynos_dp_device *dp, - u8 adjust_request[2]) -{ - int lane, lane_count; - u8 voltage_swing, pre_emphasis, training_lane; - - lane_count = dp->link_train.lane_count; - for (lane = 0; lane < lane_count; lane++) { - voltage_swing = exynos_dp_get_adjust_request_voltage( - adjust_request, lane); - pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( - adjust_request, lane); - training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | - DPCD_PRE_EMPHASIS_SET(pre_emphasis); - - if (voltage_swing == VOLTAGE_LEVEL_3) - training_lane |= DPCD_MAX_SWING_REACHED; - if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) - training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; - - dp->link_train.training_lane[lane] = training_lane; - } -} - -static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) -{ - int lane, lane_count, retval; - u8 voltage_swing, pre_emphasis, training_lane; - u8 link_status[2], adjust_request[2]; - - usleep_range(100, 101); - - lane_count = dp->link_train.lane_count; - - retval = exynos_dp_read_bytes_from_dpcd(dp, - DPCD_ADDR_LANE0_1_STATUS, 2, link_status); - if (retval) - return retval; - - retval = exynos_dp_read_bytes_from_dpcd(dp, - DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request); - if (retval) - return retval; - - if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { - /* set training pattern 2 for EQ */ - exynos_dp_set_training_pattern(dp, TRAINING_PTN2); - - retval = exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - DPCD_SCRAMBLING_DISABLED | - DPCD_TRAINING_PATTERN_2); - if (retval) - return retval; - - dev_info(dp->dev, "Link Training Clock Recovery success\n"); - dp->link_train.lt_state = EQUALIZER_TRAINING; - } else { - for (lane = 0; lane < lane_count; lane++) { - training_lane = exynos_dp_get_lane_link_training( - dp, lane); - voltage_swing = exynos_dp_get_adjust_request_voltage( - adjust_request, lane); - pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( - adjust_request, lane); - - if (DPCD_VOLTAGE_SWING_GET(training_lane) == - voltage_swing && - DPCD_PRE_EMPHASIS_GET(training_lane) == - pre_emphasis) - dp->link_train.cr_loop[lane]++; - - if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP || - voltage_swing == VOLTAGE_LEVEL_3 || - pre_emphasis == PRE_EMPHASIS_LEVEL_3) { - dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n", - dp->link_train.cr_loop[lane], - voltage_swing, pre_emphasis); - exynos_dp_reduce_link_rate(dp); - return -EIO; - } - } - } - - exynos_dp_get_adjust_training_lane(dp, adjust_request); - - for (lane = 0; lane < lane_count; lane++) - exynos_dp_set_lane_link_training(dp, - dp->link_train.training_lane[lane], lane); - - retval = exynos_dp_write_bytes_to_dpcd(dp, - DPCD_ADDR_TRAINING_LANE0_SET, lane_count, - dp->link_train.training_lane); - if (retval) - return retval; - - return retval; -} - -static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) -{ - int lane, lane_count, retval; - u32 reg; - u8 link_align, link_status[2], adjust_request[2]; - - usleep_range(400, 401); - - lane_count = dp->link_train.lane_count; - - retval = exynos_dp_read_bytes_from_dpcd(dp, - DPCD_ADDR_LANE0_1_STATUS, 2, link_status); - if (retval) - return retval; - - if (exynos_dp_clock_recovery_ok(link_status, lane_count)) { - exynos_dp_reduce_link_rate(dp); - return -EIO; - } - - retval = exynos_dp_read_bytes_from_dpcd(dp, - DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request); - if (retval) - return retval; - - retval = exynos_dp_read_byte_from_dpcd(dp, - DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, &link_align); - if (retval) - return retval; - - exynos_dp_get_adjust_training_lane(dp, adjust_request); - - if (!exynos_dp_channel_eq_ok(link_status, link_align, lane_count)) { - /* traing pattern Set to Normal */ - exynos_dp_training_pattern_dis(dp); - - dev_info(dp->dev, "Link Training success!\n"); - - exynos_dp_get_link_bandwidth(dp, ®); - dp->link_train.link_rate = reg; - dev_dbg(dp->dev, "final bandwidth = %.2x\n", - dp->link_train.link_rate); - - exynos_dp_get_lane_count(dp, ®); - dp->link_train.lane_count = reg; - dev_dbg(dp->dev, "final lane count = %.2x\n", - dp->link_train.lane_count); - - /* set enhanced mode if available */ - exynos_dp_set_enhanced_mode(dp); - dp->link_train.lt_state = FINISHED; - - return 0; - } - - /* not all locked */ - dp->link_train.eq_loop++; - - if (dp->link_train.eq_loop > MAX_EQ_LOOP) { - dev_err(dp->dev, "EQ Max loop\n"); - exynos_dp_reduce_link_rate(dp); - return -EIO; - } - - for (lane = 0; lane < lane_count; lane++) - exynos_dp_set_lane_link_training(dp, - dp->link_train.training_lane[lane], lane); - - retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET, - lane_count, dp->link_train.training_lane); - - return retval; -} - -static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp, - u8 *bandwidth) -{ - u8 data; - - /* - * For DP rev.1.1, Maximum link rate of Main Link lanes - * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps - */ - exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data); - *bandwidth = data; -} - -static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp, - u8 *lane_count) -{ - u8 data; - - /* - * For DP rev.1.1, Maximum number of Main Link lanes - * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes - */ - exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data); - *lane_count = DPCD_MAX_LANE_COUNT(data); -} - -static void exynos_dp_init_training(struct exynos_dp_device *dp, - enum link_lane_count_type max_lane, - enum link_rate_type max_rate) -{ - /* - * MACRO_RST must be applied after the PLL_LOCK to avoid - * the DP inter pair skew issue for at least 10 us - */ - exynos_dp_reset_macro(dp); - - /* Initialize by reading RX's DPCD */ - exynos_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate); - exynos_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count); - - if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) && - (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) { - dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n", - dp->link_train.link_rate); - dp->link_train.link_rate = LINK_RATE_1_62GBPS; - } - - if (dp->link_train.lane_count == 0) { - dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n", - dp->link_train.lane_count); - dp->link_train.lane_count = (u8)LANE_COUNT1; - } - - /* Setup TX lane count & rate */ - if (dp->link_train.lane_count > max_lane) - dp->link_train.lane_count = max_lane; - if (dp->link_train.link_rate > max_rate) - dp->link_train.link_rate = max_rate; - - /* All DP analog module power up */ - exynos_dp_set_analog_power_down(dp, POWER_ALL, 0); -} - -static int exynos_dp_sw_link_training(struct exynos_dp_device *dp) -{ - int retval = 0, training_finished = 0; - - dp->link_train.lt_state = START; - - /* Process here */ - while (!retval && !training_finished) { - switch (dp->link_train.lt_state) { - case START: - retval = exynos_dp_link_start(dp); - if (retval) - dev_err(dp->dev, "LT link start failed!\n"); - break; - case CLOCK_RECOVERY: - retval = exynos_dp_process_clock_recovery(dp); - if (retval) - dev_err(dp->dev, "LT CR failed!\n"); - break; - case EQUALIZER_TRAINING: - retval = exynos_dp_process_equalizer_training(dp); - if (retval) - dev_err(dp->dev, "LT EQ failed!\n"); - break; - case FINISHED: - training_finished = 1; - break; - case FAILED: - return -EREMOTEIO; - } - } - if (retval) - dev_err(dp->dev, "eDP link training failed (%d)\n", retval); - - return retval; -} - -static int exynos_dp_set_link_train(struct exynos_dp_device *dp, - u32 count, - u32 bwtype) -{ - int i; - int retval; - - for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) { - exynos_dp_init_training(dp, count, bwtype); - retval = exynos_dp_sw_link_training(dp); - if (retval == 0) - break; - - usleep_range(100, 110); - } - - return retval; -} - -static int exynos_dp_config_video(struct exynos_dp_device *dp) -{ - int retval = 0; - int timeout_loop = 0; - int done_count = 0; - - exynos_dp_config_video_slave_mode(dp); - - exynos_dp_set_video_color_format(dp); - - if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { - dev_err(dp->dev, "PLL is not locked yet.\n"); - return -EINVAL; - } - - for (;;) { - timeout_loop++; - if (exynos_dp_is_slave_video_stream_clock_on(dp) == 0) - break; - if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { - dev_err(dp->dev, "Timeout of video streamclk ok\n"); - return -ETIMEDOUT; - } - - usleep_range(1, 2); - } - - /* Set to use the register calculated M/N video */ - exynos_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0); - - /* For video bist, Video timing must be generated by register */ - exynos_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE); - - /* Disable video mute */ - exynos_dp_enable_video_mute(dp, 0); - - /* Configure video slave mode */ - exynos_dp_enable_video_master(dp, 0); - - /* Enable video */ - exynos_dp_start_video(dp); - - timeout_loop = 0; - - for (;;) { - timeout_loop++; - if (exynos_dp_is_video_stream_on(dp) == 0) { - done_count++; - if (done_count > 10) - break; - } else if (done_count) { - done_count = 0; - } - if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { - dev_err(dp->dev, "Timeout of video streamclk ok\n"); - return -ETIMEDOUT; - } - - usleep_range(1000, 1001); - } - - if (retval != 0) - dev_err(dp->dev, "Video stream is not detected!\n"); - - return retval; -} - -static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable) -{ - u8 data; - - if (enable) { - exynos_dp_enable_scrambling(dp); - - exynos_dp_read_byte_from_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - &data); - exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - (u8)(data & ~DPCD_SCRAMBLING_DISABLED)); - } else { - exynos_dp_disable_scrambling(dp); - - exynos_dp_read_byte_from_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - &data); - exynos_dp_write_byte_to_dpcd(dp, - DPCD_ADDR_TRAINING_PATTERN_SET, - (u8)(data | DPCD_SCRAMBLING_DISABLED)); - } -} - -static irqreturn_t exynos_dp_irq_handler(int irq, void *arg) -{ - struct exynos_dp_device *dp = arg; - - enum dp_irq_type irq_type; - - irq_type = exynos_dp_get_irq_type(dp); - switch (irq_type) { - case DP_IRQ_TYPE_HP_CABLE_IN: - dev_dbg(dp->dev, "Received irq - cable in\n"); - schedule_work(&dp->hotplug_work); - exynos_dp_clear_hotplug_interrupts(dp); - break; - case DP_IRQ_TYPE_HP_CABLE_OUT: - dev_dbg(dp->dev, "Received irq - cable out\n"); - exynos_dp_clear_hotplug_interrupts(dp); - break; - case DP_IRQ_TYPE_HP_CHANGE: - /* - * We get these change notifications once in a while, but there - * is nothing we can do with them. Just ignore it for now and - * only handle cable changes. - */ - dev_dbg(dp->dev, "Received irq - hotplug change; ignoring.\n"); - exynos_dp_clear_hotplug_interrupts(dp); - break; - default: - dev_err(dp->dev, "Received irq - unknown type!\n"); - break; - } - return IRQ_HANDLED; -} - -static void exynos_dp_hotplug(struct work_struct *work) -{ - struct exynos_dp_device *dp; - int ret; - - dp = container_of(work, struct exynos_dp_device, hotplug_work); - - ret = exynos_dp_detect_hpd(dp); - if (ret) { - /* Cable has been disconnected, we're done */ - return; - } - - ret = exynos_dp_handle_edid(dp); - if (ret) { - dev_err(dp->dev, "unable to handle edid\n"); - return; - } - - ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count, - dp->video_info->link_rate); - if (ret) { - dev_err(dp->dev, "unable to do link train\n"); - return; - } - - exynos_dp_enable_scramble(dp, 1); - exynos_dp_enable_rx_to_enhanced_mode(dp, 1); - exynos_dp_enable_enhanced_mode(dp, 1); - - exynos_dp_set_lane_count(dp, dp->video_info->lane_count); - exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate); - - exynos_dp_init_video(dp); - ret = exynos_dp_config_video(dp); - if (ret) - dev_err(dp->dev, "unable to config video\n"); -} - -static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev) -{ - struct device_node *dp_node = dev->of_node; - struct video_info *dp_video_config; - - dp_video_config = devm_kzalloc(dev, - sizeof(*dp_video_config), GFP_KERNEL); - if (!dp_video_config) { - dev_err(dev, "memory allocation for video config failed\n"); - return ERR_PTR(-ENOMEM); - } - - dp_video_config->h_sync_polarity = - of_property_read_bool(dp_node, "hsync-active-high"); - - dp_video_config->v_sync_polarity = - of_property_read_bool(dp_node, "vsync-active-high"); - - dp_video_config->interlaced = - of_property_read_bool(dp_node, "interlaced"); - - if (of_property_read_u32(dp_node, "samsung,color-space", - &dp_video_config->color_space)) { - dev_err(dev, "failed to get color-space\n"); - return ERR_PTR(-EINVAL); - } - - if (of_property_read_u32(dp_node, "samsung,dynamic-range", - &dp_video_config->dynamic_range)) { - dev_err(dev, "failed to get dynamic-range\n"); - return ERR_PTR(-EINVAL); - } - - if (of_property_read_u32(dp_node, "samsung,ycbcr-coeff", - &dp_video_config->ycbcr_coeff)) { - dev_err(dev, "failed to get ycbcr-coeff\n"); - return ERR_PTR(-EINVAL); - } - - if (of_property_read_u32(dp_node, "samsung,color-depth", - &dp_video_config->color_depth)) { - dev_err(dev, "failed to get color-depth\n"); - return ERR_PTR(-EINVAL); - } - - if (of_property_read_u32(dp_node, "samsung,link-rate", - &dp_video_config->link_rate)) { - dev_err(dev, "failed to get link-rate\n"); - return ERR_PTR(-EINVAL); - } - - if (of_property_read_u32(dp_node, "samsung,lane-count", - &dp_video_config->lane_count)) { - dev_err(dev, "failed to get lane-count\n"); - return ERR_PTR(-EINVAL); - } - - return dp_video_config; -} - -static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp) -{ - struct device_node *dp_phy_node = of_node_get(dp->dev->of_node); - u32 phy_base; - int ret = 0; - - dp_phy_node = of_find_node_by_name(dp_phy_node, "dptx-phy"); - if (!dp_phy_node) { - dp->phy = devm_phy_get(dp->dev, "dp"); - if (IS_ERR(dp->phy)) - return PTR_ERR(dp->phy); - else - return 0; - } - - if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) { - dev_err(dp->dev, "failed to get reg for dptx-phy\n"); - ret = -EINVAL; - goto err; - } - - if (of_property_read_u32(dp_phy_node, "samsung,enable-mask", - &dp->enable_mask)) { - dev_err(dp->dev, "failed to get enable-mask for dptx-phy\n"); - ret = -EINVAL; - goto err; - } - - dp->phy_addr = ioremap(phy_base, SZ_4); - if (!dp->phy_addr) { - dev_err(dp->dev, "failed to ioremap dp-phy\n"); - ret = -ENOMEM; - goto err; - } - -err: - of_node_put(dp_phy_node); - - return ret; -} - -static void exynos_dp_phy_init(struct exynos_dp_device *dp) -{ - if (dp->phy) { - phy_power_on(dp->phy); - } else if (dp->phy_addr) { - u32 reg; - - reg = __raw_readl(dp->phy_addr); - reg |= dp->enable_mask; - __raw_writel(reg, dp->phy_addr); - } -} - -static void exynos_dp_phy_exit(struct exynos_dp_device *dp) -{ - if (dp->phy) { - phy_power_off(dp->phy); - } else if (dp->phy_addr) { - u32 reg; - - reg = __raw_readl(dp->phy_addr); - reg &= ~(dp->enable_mask); - __raw_writel(reg, dp->phy_addr); - } -} - -static int exynos_dp_probe(struct platform_device *pdev) -{ - struct resource *res; - struct exynos_dp_device *dp; - - int ret = 0; - - dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), - GFP_KERNEL); - if (!dp) { - dev_err(&pdev->dev, "no memory for device data\n"); - return -ENOMEM; - } - - dp->dev = &pdev->dev; - - dp->video_info = exynos_dp_dt_parse_pdata(&pdev->dev); - if (IS_ERR(dp->video_info)) - return PTR_ERR(dp->video_info); - - ret = exynos_dp_dt_parse_phydata(dp); - if (ret) - return ret; - - dp->clock = devm_clk_get(&pdev->dev, "dp"); - if (IS_ERR(dp->clock)) { - dev_err(&pdev->dev, "failed to get clock\n"); - return PTR_ERR(dp->clock); - } - - clk_prepare_enable(dp->clock); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - dp->reg_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(dp->reg_base)) - return PTR_ERR(dp->reg_base); - - dp->irq = platform_get_irq(pdev, 0); - if (dp->irq == -ENXIO) { - dev_err(&pdev->dev, "failed to get irq\n"); - return -ENODEV; - } - - INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug); - - exynos_dp_phy_init(dp); - - exynos_dp_init_dp(dp); - - ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0, - "exynos-dp", dp); - if (ret) { - dev_err(&pdev->dev, "failed to request irq\n"); - return ret; - } - - platform_set_drvdata(pdev, dp); - - return 0; -} - -static int exynos_dp_remove(struct platform_device *pdev) -{ - struct exynos_dp_device *dp = platform_get_drvdata(pdev); - - flush_work(&dp->hotplug_work); - - exynos_dp_phy_exit(dp); - - clk_disable_unprepare(dp->clock); - - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int exynos_dp_suspend(struct device *dev) -{ - struct exynos_dp_device *dp = dev_get_drvdata(dev); - - disable_irq(dp->irq); - - flush_work(&dp->hotplug_work); - - exynos_dp_phy_exit(dp); - - clk_disable_unprepare(dp->clock); - - return 0; -} - -static int exynos_dp_resume(struct device *dev) -{ - struct exynos_dp_device *dp = dev_get_drvdata(dev); - - exynos_dp_phy_init(dp); - - clk_prepare_enable(dp->clock); - - exynos_dp_init_dp(dp); - - enable_irq(dp->irq); - - return 0; -} -#endif - -static const struct dev_pm_ops exynos_dp_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume) -}; - -static const struct of_device_id exynos_dp_match[] = { - { .compatible = "samsung,exynos5-dp" }, - {}, -}; -MODULE_DEVICE_TABLE(of, exynos_dp_match); - -static struct platform_driver exynos_dp_driver = { - .probe = exynos_dp_probe, - .remove = exynos_dp_remove, - .driver = { - .name = "exynos-dp", - .owner = THIS_MODULE, - .pm = &exynos_dp_pm_ops, - .of_match_table = exynos_dp_match, - }, -}; - -module_platform_driver(exynos_dp_driver); - -MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); -MODULE_DESCRIPTION("Samsung SoC DP Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/video/exynos/exynos_dp_core.h deleted file mode 100644 index 607e36d0c147..000000000000 --- a/drivers/video/exynos/exynos_dp_core.h +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Header file for Samsung DP (Display Port) interface driver. - * - * Copyright (C) 2012 Samsung Electronics Co., Ltd. - * Author: Jingoo Han <jg1.han@samsung.com> - * - * 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 _EXYNOS_DP_CORE_H -#define _EXYNOS_DP_CORE_H - -#define DP_TIMEOUT_LOOP_COUNT 100 -#define MAX_CR_LOOP 5 -#define MAX_EQ_LOOP 5 - -enum link_rate_type { - LINK_RATE_1_62GBPS = 0x06, - LINK_RATE_2_70GBPS = 0x0a -}; - -enum link_lane_count_type { - LANE_COUNT1 = 1, - LANE_COUNT2 = 2, - LANE_COUNT4 = 4 -}; - -enum link_training_state { - START, - CLOCK_RECOVERY, - EQUALIZER_TRAINING, - FINISHED, - FAILED -}; - -enum voltage_swing_level { - VOLTAGE_LEVEL_0, - VOLTAGE_LEVEL_1, - VOLTAGE_LEVEL_2, - VOLTAGE_LEVEL_3, -}; - -enum pre_emphasis_level { - PRE_EMPHASIS_LEVEL_0, - PRE_EMPHASIS_LEVEL_1, - PRE_EMPHASIS_LEVEL_2, - PRE_EMPHASIS_LEVEL_3, -}; - -enum pattern_set { - PRBS7, - D10_2, - TRAINING_PTN1, - TRAINING_PTN2, - DP_NONE -}; - -enum color_space { - COLOR_RGB, - COLOR_YCBCR422, - COLOR_YCBCR444 -}; - -enum color_depth { - COLOR_6, - COLOR_8, - COLOR_10, - COLOR_12 -}; - -enum color_coefficient { - COLOR_YCBCR601, - COLOR_YCBCR709 -}; - -enum dynamic_range { - VESA, - CEA -}; - -enum pll_status { - PLL_UNLOCKED, - PLL_LOCKED -}; - -enum clock_recovery_m_value_type { - CALCULATED_M, - REGISTER_M -}; - -enum video_timing_recognition_type { - VIDEO_TIMING_FROM_CAPTURE, - VIDEO_TIMING_FROM_REGISTER -}; - -enum analog_power_block { - AUX_BLOCK, - CH0_BLOCK, - CH1_BLOCK, - CH2_BLOCK, - CH3_BLOCK, - ANALOG_TOTAL, - POWER_ALL -}; - -enum dp_irq_type { - DP_IRQ_TYPE_HP_CABLE_IN, - DP_IRQ_TYPE_HP_CABLE_OUT, - DP_IRQ_TYPE_HP_CHANGE, - DP_IRQ_TYPE_UNKNOWN, -}; - -struct video_info { - char *name; - - bool h_sync_polarity; - bool v_sync_polarity; - bool interlaced; - - enum color_space color_space; - enum dynamic_range dynamic_range; - enum color_coefficient ycbcr_coeff; - enum color_depth color_depth; - - enum link_rate_type link_rate; - enum link_lane_count_type lane_count; -}; - -struct link_train { - int eq_loop; - int cr_loop[4]; - - u8 link_rate; - u8 lane_count; - u8 training_lane[4]; - - enum link_training_state lt_state; -}; - -struct exynos_dp_device { - struct device *dev; - struct clk *clock; - unsigned int irq; - void __iomem *reg_base; - void __iomem *phy_addr; - unsigned int enable_mask; - - struct video_info *video_info; - struct link_train link_train; - struct work_struct hotplug_work; - struct phy *phy; -}; - -/* exynos_dp_reg.c */ -void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable); -void exynos_dp_stop_video(struct exynos_dp_device *dp); -void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable); -void exynos_dp_init_analog_param(struct exynos_dp_device *dp); -void exynos_dp_init_interrupt(struct exynos_dp_device *dp); -void exynos_dp_reset(struct exynos_dp_device *dp); -void exynos_dp_swreset(struct exynos_dp_device *dp); -void exynos_dp_config_interrupt(struct exynos_dp_device *dp); -enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp); -void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable); -void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp, - enum analog_power_block block, - bool enable); -void exynos_dp_init_analog_func(struct exynos_dp_device *dp); -void exynos_dp_init_hpd(struct exynos_dp_device *dp); -enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp); -void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp); -void exynos_dp_reset_aux(struct exynos_dp_device *dp); -void exynos_dp_init_aux(struct exynos_dp_device *dp); -int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp); -void exynos_dp_enable_sw_function(struct exynos_dp_device *dp); -int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp); -int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp, - unsigned int reg_addr, - unsigned char data); -int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp, - unsigned int reg_addr, - unsigned char *data); -int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp, - unsigned int reg_addr, - unsigned int count, - unsigned char data[]); -int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp, - unsigned int reg_addr, - unsigned int count, - unsigned char data[]); -int exynos_dp_select_i2c_device(struct exynos_dp_device *dp, - unsigned int device_addr, - unsigned int reg_addr); -int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp, - unsigned int device_addr, - unsigned int reg_addr, - unsigned int *data); -int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp, - unsigned int device_addr, - unsigned int reg_addr, - unsigned int count, - unsigned char edid[]); -void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype); -void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype); -void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count); -void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count); -void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable); -void exynos_dp_set_training_pattern(struct exynos_dp_device *dp, - enum pattern_set pattern); -void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level); -void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level); -void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level); -void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level); -void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp, - u32 training_lane); -void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp, - u32 training_lane); -void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp, - u32 training_lane); -void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp, - u32 training_lane); -u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp); -u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp); -u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp); -u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp); -void exynos_dp_reset_macro(struct exynos_dp_device *dp); -void exynos_dp_init_video(struct exynos_dp_device *dp); - -void exynos_dp_set_video_color_format(struct exynos_dp_device *dp); -int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp); -void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp, - enum clock_recovery_m_value_type type, - u32 m_value, - u32 n_value); -void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type); -void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable); -void exynos_dp_start_video(struct exynos_dp_device *dp); -int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp); -void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp); -void exynos_dp_enable_scrambling(struct exynos_dp_device *dp); -void exynos_dp_disable_scrambling(struct exynos_dp_device *dp); - -/* I2C EDID Chip ID, Slave Address */ -#define I2C_EDID_DEVICE_ADDR 0x50 -#define I2C_E_EDID_DEVICE_ADDR 0x30 - -#define EDID_BLOCK_LENGTH 0x80 -#define EDID_HEADER_PATTERN 0x00 -#define EDID_EXTENSION_FLAG 0x7e -#define EDID_CHECKSUM 0x7f - -/* Definition for DPCD Register */ -#define DPCD_ADDR_DPCD_REV 0x0000 -#define DPCD_ADDR_MAX_LINK_RATE 0x0001 -#define DPCD_ADDR_MAX_LANE_COUNT 0x0002 -#define DPCD_ADDR_LINK_BW_SET 0x0100 -#define DPCD_ADDR_LANE_COUNT_SET 0x0101 -#define DPCD_ADDR_TRAINING_PATTERN_SET 0x0102 -#define DPCD_ADDR_TRAINING_LANE0_SET 0x0103 -#define DPCD_ADDR_LANE0_1_STATUS 0x0202 -#define DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED 0x0204 -#define DPCD_ADDR_ADJUST_REQUEST_LANE0_1 0x0206 -#define DPCD_ADDR_ADJUST_REQUEST_LANE2_3 0x0207 -#define DPCD_ADDR_TEST_REQUEST 0x0218 -#define DPCD_ADDR_TEST_RESPONSE 0x0260 -#define DPCD_ADDR_TEST_EDID_CHECKSUM 0x0261 -#define DPCD_ADDR_SINK_POWER_STATE 0x0600 - -/* DPCD_ADDR_MAX_LANE_COUNT */ -#define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) -#define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) - -/* DPCD_ADDR_LANE_COUNT_SET */ -#define DPCD_ENHANCED_FRAME_EN (0x1 << 7) -#define DPCD_LANE_COUNT_SET(x) ((x) & 0x1f) - -/* DPCD_ADDR_TRAINING_PATTERN_SET */ -#define DPCD_SCRAMBLING_DISABLED (0x1 << 5) -#define DPCD_SCRAMBLING_ENABLED (0x0 << 5) -#define DPCD_TRAINING_PATTERN_2 (0x2 << 0) -#define DPCD_TRAINING_PATTERN_1 (0x1 << 0) -#define DPCD_TRAINING_PATTERN_DISABLED (0x0 << 0) - -/* DPCD_ADDR_TRAINING_LANE0_SET */ -#define DPCD_MAX_PRE_EMPHASIS_REACHED (0x1 << 5) -#define DPCD_PRE_EMPHASIS_SET(x) (((x) & 0x3) << 3) -#define DPCD_PRE_EMPHASIS_GET(x) (((x) >> 3) & 0x3) -#define DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 (0x0 << 3) -#define DPCD_MAX_SWING_REACHED (0x1 << 2) -#define DPCD_VOLTAGE_SWING_SET(x) (((x) & 0x3) << 0) -#define DPCD_VOLTAGE_SWING_GET(x) (((x) >> 0) & 0x3) -#define DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0 (0x0 << 0) - -/* DPCD_ADDR_LANE0_1_STATUS */ -#define DPCD_LANE_SYMBOL_LOCKED (0x1 << 2) -#define DPCD_LANE_CHANNEL_EQ_DONE (0x1 << 1) -#define DPCD_LANE_CR_DONE (0x1 << 0) -#define DPCD_CHANNEL_EQ_BITS (DPCD_LANE_CR_DONE| \ - DPCD_LANE_CHANNEL_EQ_DONE|\ - DPCD_LANE_SYMBOL_LOCKED) - -/* DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED */ -#define DPCD_LINK_STATUS_UPDATED (0x1 << 7) -#define DPCD_DOWNSTREAM_PORT_STATUS_CHANGED (0x1 << 6) -#define DPCD_INTERLANE_ALIGN_DONE (0x1 << 0) - -/* DPCD_ADDR_TEST_REQUEST */ -#define DPCD_TEST_EDID_READ (0x1 << 2) - -/* DPCD_ADDR_TEST_RESPONSE */ -#define DPCD_TEST_EDID_CHECKSUM_WRITE (0x1 << 2) - -/* DPCD_ADDR_SINK_POWER_STATE */ -#define DPCD_SET_POWER_STATE_D0 (0x1 << 0) -#define DPCD_SET_POWER_STATE_D4 (0x2 << 0) - -#endif /* _EXYNOS_DP_CORE_H */ diff --git a/drivers/video/exynos/exynos_dp_reg.c b/drivers/video/exynos/exynos_dp_reg.c deleted file mode 100644 index b70da5052ff0..000000000000 --- a/drivers/video/exynos/exynos_dp_reg.c +++ /dev/null @@ -1,1243 +0,0 @@ -/* - * Samsung DP (Display port) register interface driver. - * - * Copyright (C) 2012 Samsung Electronics Co., Ltd. - * Author: Jingoo Han <jg1.han@samsung.com> - * - * 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. - */ - -#include <linux/device.h> -#include <linux/io.h> -#include <linux/delay.h> - -#include "exynos_dp_core.h" -#include "exynos_dp_reg.h" - -#define COMMON_INT_MASK_1 0 -#define COMMON_INT_MASK_2 0 -#define COMMON_INT_MASK_3 0 -#define COMMON_INT_MASK_4 (HOTPLUG_CHG | HPD_LOST | PLUG) -#define INT_STA_MASK INT_HPD - -void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable) -{ - u32 reg; - - if (enable) { - reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); - reg |= HDCP_VIDEO_MUTE; - writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); - } else { - reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); - reg &= ~HDCP_VIDEO_MUTE; - writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); - } -} - -void exynos_dp_stop_video(struct exynos_dp_device *dp) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); - reg &= ~VIDEO_EN; - writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); -} - -void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable) -{ - u32 reg; - - if (enable) - reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 | - LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3; - else - reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 | - LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0; - - writel(reg, dp->reg_base + EXYNOS_DP_LANE_MAP); -} - -void exynos_dp_init_analog_param(struct exynos_dp_device *dp) -{ - u32 reg; - - reg = TX_TERMINAL_CTRL_50_OHM; - writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_1); - - reg = SEL_24M | TX_DVDD_BIT_1_0625V; - writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_2); - - reg = DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO; - writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_3); - - reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM | - TX_CUR1_2X | TX_CUR_16_MA; - writel(reg, dp->reg_base + EXYNOS_DP_PLL_FILTER_CTL_1); - - reg = CH3_AMP_400_MV | CH2_AMP_400_MV | - CH1_AMP_400_MV | CH0_AMP_400_MV; - writel(reg, dp->reg_base + EXYNOS_DP_TX_AMP_TUNING_CTL); -} - -void exynos_dp_init_interrupt(struct exynos_dp_device *dp) -{ - /* Set interrupt pin assertion polarity as high */ - writel(INT_POL1 | INT_POL0, dp->reg_base + EXYNOS_DP_INT_CTL); - - /* Clear pending regisers */ - writel(0xff, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1); - writel(0x4f, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_2); - writel(0xe0, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_3); - writel(0xe7, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4); - writel(0x63, dp->reg_base + EXYNOS_DP_INT_STA); - - /* 0:mask,1: unmask */ - writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1); - writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2); - writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3); - writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4); - writel(0x00, dp->reg_base + EXYNOS_DP_INT_STA_MASK); -} - -void exynos_dp_reset(struct exynos_dp_device *dp) -{ - u32 reg; - - exynos_dp_stop_video(dp); - exynos_dp_enable_video_mute(dp, 0); - - reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N | - AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N | - HDCP_FUNC_EN_N | SW_FUNC_EN_N; - writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1); - - reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N | - SERDES_FIFO_FUNC_EN_N | - LS_CLK_DOMAIN_FUNC_EN_N; - writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); - - usleep_range(20, 30); - - exynos_dp_lane_swap(dp, 0); - - writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_1); - writel(0x40, dp->reg_base + EXYNOS_DP_SYS_CTL_2); - writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_3); - writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_4); - - writel(0x0, dp->reg_base + EXYNOS_DP_PKT_SEND_CTL); - writel(0x0, dp->reg_base + EXYNOS_DP_HDCP_CTL); - - writel(0x5e, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_L); - writel(0x1a, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_H); - - writel(0x10, dp->reg_base + EXYNOS_DP_LINK_DEBUG_CTL); - - writel(0x0, dp->reg_base + EXYNOS_DP_PHY_TEST); - - writel(0x0, dp->reg_base + EXYNOS_DP_VIDEO_FIFO_THRD); - writel(0x20, dp->reg_base + EXYNOS_DP_AUDIO_MARGIN); - - writel(0x4, dp->reg_base + EXYNOS_DP_M_VID_GEN_FILTER_TH); - writel(0x2, dp->reg_base + EXYNOS_DP_M_AUD_GEN_FILTER_TH); - - writel(0x00000101, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); -} - -void exynos_dp_swreset(struct exynos_dp_device *dp) -{ - writel(RESET_DP_TX, dp->reg_base + EXYNOS_DP_TX_SW_RESET); -} - -void exynos_dp_config_interrupt(struct exynos_dp_device *dp) -{ - u32 reg; - - /* 0: mask, 1: unmask */ - reg = COMMON_INT_MASK_1; - writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1); - - reg = COMMON_INT_MASK_2; - writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2); - - reg = COMMON_INT_MASK_3; - writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3); - - reg = COMMON_INT_MASK_4; - writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4); - - reg = INT_STA_MASK; - writel(reg, dp->reg_base + EXYNOS_DP_INT_STA_MASK); -} - -enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL); - if (reg & PLL_LOCK) - return PLL_LOCKED; - else - return PLL_UNLOCKED; -} - -void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable) -{ - u32 reg; - - if (enable) { - reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL); - reg |= DP_PLL_PD; - writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL); - } else { - reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL); - reg &= ~DP_PLL_PD; - writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL); - } -} - -void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp, - enum analog_power_block block, - bool enable) -{ - u32 reg; - - switch (block) { - case AUX_BLOCK: - if (enable) { - reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); - reg |= AUX_PD; - writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); - } else { - reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); - reg &= ~AUX_PD; - writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); - } - break; - case CH0_BLOCK: - if (enable) { - reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); - reg |= CH0_PD; - writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); - } else { - reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); - reg &= ~CH0_PD; - writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); - } - break; - case CH1_BLOCK: - if (enable) { - reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); - reg |= CH1_PD; - writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); - } else { - reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); - reg &= ~CH1_PD; - writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); - } - break; - case CH2_BLOCK: - if (enable) { - reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); - reg |= CH2_PD; - writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); - } else { - reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); - reg &= ~CH2_PD; - writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); - } - break; - case CH3_BLOCK: - if (enable) { - reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); - reg |= CH3_PD; - writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); - } else { - reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); - reg &= ~CH3_PD; - writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); - } - break; - case ANALOG_TOTAL: - if (enable) { - reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); - reg |= DP_PHY_PD; - writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); - } else { - reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); - reg &= ~DP_PHY_PD; - writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); - } - break; - case POWER_ALL: - if (enable) { - reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD | - CH1_PD | CH0_PD; - writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); - } else { - writel(0x00, dp->reg_base + EXYNOS_DP_PHY_PD); - } - break; - default: - break; - } -} - -void exynos_dp_init_analog_func(struct exynos_dp_device *dp) -{ - u32 reg; - int timeout_loop = 0; - - exynos_dp_set_analog_power_down(dp, POWER_ALL, 0); - - reg = PLL_LOCK_CHG; - writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1); - - reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL); - reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL); - writel(reg, dp->reg_base + EXYNOS_DP_DEBUG_CTL); - - /* Power up PLL */ - if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { - exynos_dp_set_pll_power_down(dp, 0); - - while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { - timeout_loop++; - if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { - dev_err(dp->dev, "failed to get pll lock status\n"); - return; - } - usleep_range(10, 20); - } - } - - /* Enable Serdes FIFO function and Link symbol clock domain module */ - reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2); - reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N - | AUX_FUNC_EN_N); - writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); -} - -void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp) -{ - u32 reg; - - reg = HOTPLUG_CHG | HPD_LOST | PLUG; - writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4); - - reg = INT_HPD; - writel(reg, dp->reg_base + EXYNOS_DP_INT_STA); -} - -void exynos_dp_init_hpd(struct exynos_dp_device *dp) -{ - u32 reg; - - exynos_dp_clear_hotplug_interrupts(dp); - - reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); - reg &= ~(F_HPD | HPD_CTRL); - writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3); -} - -enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp) -{ - u32 reg; - - /* Parse hotplug interrupt status register */ - reg = readl(dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4); - - if (reg & PLUG) - return DP_IRQ_TYPE_HP_CABLE_IN; - - if (reg & HPD_LOST) - return DP_IRQ_TYPE_HP_CABLE_OUT; - - if (reg & HOTPLUG_CHG) - return DP_IRQ_TYPE_HP_CHANGE; - - return DP_IRQ_TYPE_UNKNOWN; -} - -void exynos_dp_reset_aux(struct exynos_dp_device *dp) -{ - u32 reg; - - /* Disable AUX channel module */ - reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2); - reg |= AUX_FUNC_EN_N; - writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); -} - -void exynos_dp_init_aux(struct exynos_dp_device *dp) -{ - u32 reg; - - /* Clear inerrupts related to AUX channel */ - reg = RPLY_RECEIV | AUX_ERR; - writel(reg, dp->reg_base + EXYNOS_DP_INT_STA); - - exynos_dp_reset_aux(dp); - - /* Disable AUX transaction H/W retry */ - reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(0)| - AUX_HW_RETRY_INTERVAL_600_MICROSECONDS; - writel(reg, dp->reg_base + EXYNOS_DP_AUX_HW_RETRY_CTL) ; - - /* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */ - reg = DEFER_CTRL_EN | DEFER_COUNT(1); - writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_DEFER_CTL); - - /* Enable AUX channel module */ - reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2); - reg &= ~AUX_FUNC_EN_N; - writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); -} - -int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); - if (reg & HPD_STATUS) - return 0; - - return -EINVAL; -} - -void exynos_dp_enable_sw_function(struct exynos_dp_device *dp) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1); - reg &= ~SW_FUNC_EN_N; - writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1); -} - -int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp) -{ - int reg; - int retval = 0; - int timeout_loop = 0; - - /* Enable AUX CH operation */ - reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2); - reg |= AUX_EN; - writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2); - - /* Is AUX CH command reply received? */ - reg = readl(dp->reg_base + EXYNOS_DP_INT_STA); - while (!(reg & RPLY_RECEIV)) { - timeout_loop++; - if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { - dev_err(dp->dev, "AUX CH command reply failed!\n"); - return -ETIMEDOUT; - } - reg = readl(dp->reg_base + EXYNOS_DP_INT_STA); - usleep_range(10, 11); - } - - /* Clear interrupt source for AUX CH command reply */ - writel(RPLY_RECEIV, dp->reg_base + EXYNOS_DP_INT_STA); - - /* Clear interrupt source for AUX CH access error */ - reg = readl(dp->reg_base + EXYNOS_DP_INT_STA); - if (reg & AUX_ERR) { - writel(AUX_ERR, dp->reg_base + EXYNOS_DP_INT_STA); - return -EREMOTEIO; - } - - /* Check AUX CH error access status */ - reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_STA); - if ((reg & AUX_STATUS_MASK) != 0) { - dev_err(dp->dev, "AUX CH error happens: %d\n\n", - reg & AUX_STATUS_MASK); - return -EREMOTEIO; - } - - return retval; -} - -int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp, - unsigned int reg_addr, - unsigned char data) -{ - u32 reg; - int i; - int retval; - - for (i = 0; i < 3; i++) { - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); - - /* Select DPCD device address */ - reg = AUX_ADDR_7_0(reg_addr); - writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); - reg = AUX_ADDR_15_8(reg_addr); - writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); - reg = AUX_ADDR_19_16(reg_addr); - writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); - - /* Write data buffer */ - reg = (unsigned int)data; - writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0); - - /* - * Set DisplayPort transaction and write 1 byte - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; - writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = exynos_dp_start_aux_transaction(dp); - if (retval == 0) - break; - else - dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", - __func__); - } - - return retval; -} - -int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp, - unsigned int reg_addr, - unsigned char *data) -{ - u32 reg; - int i; - int retval; - - for (i = 0; i < 3; i++) { - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); - - /* Select DPCD device address */ - reg = AUX_ADDR_7_0(reg_addr); - writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); - reg = AUX_ADDR_15_8(reg_addr); - writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); - reg = AUX_ADDR_19_16(reg_addr); - writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); - - /* - * Set DisplayPort transaction and read 1 byte - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; - writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = exynos_dp_start_aux_transaction(dp); - if (retval == 0) - break; - else - dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", - __func__); - } - - /* Read data buffer */ - reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0); - *data = (unsigned char)(reg & 0xff); - - return retval; -} - -int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp, - unsigned int reg_addr, - unsigned int count, - unsigned char data[]) -{ - u32 reg; - unsigned int start_offset; - unsigned int cur_data_count; - unsigned int cur_data_idx; - int i; - int retval = 0; - - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); - - start_offset = 0; - while (start_offset < count) { - /* Buffer size of AUX CH is 16 * 4bytes */ - if ((count - start_offset) > 16) - cur_data_count = 16; - else - cur_data_count = count - start_offset; - - for (i = 0; i < 3; i++) { - /* Select DPCD device address */ - reg = AUX_ADDR_7_0(reg_addr + start_offset); - writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); - reg = AUX_ADDR_15_8(reg_addr + start_offset); - writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); - reg = AUX_ADDR_19_16(reg_addr + start_offset); - writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); - - for (cur_data_idx = 0; cur_data_idx < cur_data_count; - cur_data_idx++) { - reg = data[start_offset + cur_data_idx]; - writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0 - + 4 * cur_data_idx); - } - - /* - * Set DisplayPort transaction and write - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_LENGTH(cur_data_count) | - AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; - writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = exynos_dp_start_aux_transaction(dp); - if (retval == 0) - break; - else - dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", - __func__); - } - - start_offset += cur_data_count; - } - - return retval; -} - -int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp, - unsigned int reg_addr, - unsigned int count, - unsigned char data[]) -{ - u32 reg; - unsigned int start_offset; - unsigned int cur_data_count; - unsigned int cur_data_idx; - int i; - int retval = 0; - - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); - - start_offset = 0; - while (start_offset < count) { - /* Buffer size of AUX CH is 16 * 4bytes */ - if ((count - start_offset) > 16) - cur_data_count = 16; - else - cur_data_count = count - start_offset; - - /* AUX CH Request Transaction process */ - for (i = 0; i < 3; i++) { - /* Select DPCD device address */ - reg = AUX_ADDR_7_0(reg_addr + start_offset); - writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); - reg = AUX_ADDR_15_8(reg_addr + start_offset); - writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); - reg = AUX_ADDR_19_16(reg_addr + start_offset); - writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); - - /* - * Set DisplayPort transaction and read - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_LENGTH(cur_data_count) | - AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; - writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = exynos_dp_start_aux_transaction(dp); - if (retval == 0) - break; - else - dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", - __func__); - } - - for (cur_data_idx = 0; cur_data_idx < cur_data_count; - cur_data_idx++) { - reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0 - + 4 * cur_data_idx); - data[start_offset + cur_data_idx] = - (unsigned char)reg; - } - - start_offset += cur_data_count; - } - - return retval; -} - -int exynos_dp_select_i2c_device(struct exynos_dp_device *dp, - unsigned int device_addr, - unsigned int reg_addr) -{ - u32 reg; - int retval; - - /* Set EDID device address */ - reg = device_addr; - writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); - writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); - writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); - - /* Set offset from base address of EDID device */ - writel(reg_addr, dp->reg_base + EXYNOS_DP_BUF_DATA_0); - - /* - * Set I2C transaction and write address - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT | - AUX_TX_COMM_WRITE; - writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = exynos_dp_start_aux_transaction(dp); - if (retval != 0) - dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); - - return retval; -} - -int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp, - unsigned int device_addr, - unsigned int reg_addr, - unsigned int *data) -{ - u32 reg; - int i; - int retval; - - for (i = 0; i < 3; i++) { - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); - - /* Select EDID device */ - retval = exynos_dp_select_i2c_device(dp, device_addr, reg_addr); - if (retval != 0) - continue; - - /* - * Set I2C transaction and read data - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_TX_COMM_I2C_TRANSACTION | - AUX_TX_COMM_READ; - writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = exynos_dp_start_aux_transaction(dp); - if (retval == 0) - break; - else - dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", - __func__); - } - - /* Read data */ - if (retval == 0) - *data = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0); - - return retval; -} - -int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp, - unsigned int device_addr, - unsigned int reg_addr, - unsigned int count, - unsigned char edid[]) -{ - u32 reg; - unsigned int i, j; - unsigned int cur_data_idx; - unsigned int defer = 0; - int retval = 0; - - for (i = 0; i < count; i += 16) { - for (j = 0; j < 3; j++) { - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); - - /* Set normal AUX CH command */ - reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2); - reg &= ~ADDR_ONLY; - writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2); - - /* - * If Rx sends defer, Tx sends only reads - * request without sending address - */ - if (!defer) - retval = exynos_dp_select_i2c_device(dp, - device_addr, reg_addr + i); - else - defer = 0; - - if (retval == 0) { - /* - * Set I2C transaction and write data - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_LENGTH(16) | - AUX_TX_COMM_I2C_TRANSACTION | - AUX_TX_COMM_READ; - writel(reg, dp->reg_base + - EXYNOS_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = exynos_dp_start_aux_transaction(dp); - if (retval == 0) - break; - else - dev_dbg(dp->dev, - "%s: Aux Transaction fail!\n", - __func__); - } - /* Check if Rx sends defer */ - reg = readl(dp->reg_base + EXYNOS_DP_AUX_RX_COMM); - if (reg == AUX_RX_COMM_AUX_DEFER || - reg == AUX_RX_COMM_I2C_DEFER) { - dev_err(dp->dev, "Defer: %d\n\n", reg); - defer = 1; - } - } - - for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) { - reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0 - + 4 * cur_data_idx); - edid[i + cur_data_idx] = (unsigned char)reg; - } - } - - return retval; -} - -void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype) -{ - u32 reg; - - reg = bwtype; - if ((bwtype == LINK_RATE_2_70GBPS) || (bwtype == LINK_RATE_1_62GBPS)) - writel(reg, dp->reg_base + EXYNOS_DP_LINK_BW_SET); -} - -void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_LINK_BW_SET); - *bwtype = reg; -} - -void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count) -{ - u32 reg; - - reg = count; - writel(reg, dp->reg_base + EXYNOS_DP_LANE_COUNT_SET); -} - -void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_LANE_COUNT_SET); - *count = reg; -} - -void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable) -{ - u32 reg; - - if (enable) { - reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4); - reg |= ENHANCED; - writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4); - } else { - reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4); - reg &= ~ENHANCED; - writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4); - } -} - -void exynos_dp_set_training_pattern(struct exynos_dp_device *dp, - enum pattern_set pattern) -{ - u32 reg; - - switch (pattern) { - case PRBS7: - reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7; - writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); - break; - case D10_2: - reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2; - writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); - break; - case TRAINING_PTN1: - reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1; - writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); - break; - case TRAINING_PTN2: - reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2; - writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); - break; - case DP_NONE: - reg = SCRAMBLING_ENABLE | - LINK_QUAL_PATTERN_SET_DISABLE | - SW_TRAINING_PATTERN_SET_NORMAL; - writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); - break; - default: - break; - } -} - -void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL); - reg &= ~PRE_EMPHASIS_SET_MASK; - reg |= level << PRE_EMPHASIS_SET_SHIFT; - writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL); -} - -void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL); - reg &= ~PRE_EMPHASIS_SET_MASK; - reg |= level << PRE_EMPHASIS_SET_SHIFT; - writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL); -} - -void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL); - reg &= ~PRE_EMPHASIS_SET_MASK; - reg |= level << PRE_EMPHASIS_SET_SHIFT; - writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL); -} - -void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL); - reg &= ~PRE_EMPHASIS_SET_MASK; - reg |= level << PRE_EMPHASIS_SET_SHIFT; - writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL); -} - -void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp, - u32 training_lane) -{ - u32 reg; - - reg = training_lane; - writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL); -} - -void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp, - u32 training_lane) -{ - u32 reg; - - reg = training_lane; - writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL); -} - -void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp, - u32 training_lane) -{ - u32 reg; - - reg = training_lane; - writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL); -} - -void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp, - u32 training_lane) -{ - u32 reg; - - reg = training_lane; - writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL); -} - -u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL); - return reg; -} - -u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL); - return reg; -} - -u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL); - return reg; -} - -u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL); - return reg; -} - -void exynos_dp_reset_macro(struct exynos_dp_device *dp) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_PHY_TEST); - reg |= MACRO_RST; - writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST); - - /* 10 us is the minimum reset time. */ - usleep_range(10, 20); - - reg &= ~MACRO_RST; - writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST); -} - -void exynos_dp_init_video(struct exynos_dp_device *dp) -{ - u32 reg; - - reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG; - writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1); - - reg = 0x0; - writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1); - - reg = CHA_CRI(4) | CHA_CTRL; - writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2); - - reg = 0x0; - writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3); - - reg = VID_HRES_TH(2) | VID_VRES_TH(0); - writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8); -} - -void exynos_dp_set_video_color_format(struct exynos_dp_device *dp) -{ - u32 reg; - - /* Configure the input color depth, color space, dynamic range */ - reg = (dp->video_info->dynamic_range << IN_D_RANGE_SHIFT) | - (dp->video_info->color_depth << IN_BPC_SHIFT) | - (dp->video_info->color_space << IN_COLOR_F_SHIFT); - writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_2); - - /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */ - reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_3); - reg &= ~IN_YC_COEFFI_MASK; - if (dp->video_info->ycbcr_coeff) - reg |= IN_YC_COEFFI_ITU709; - else - reg |= IN_YC_COEFFI_ITU601; - writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_3); -} - -int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1); - writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1); - - reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1); - - if (!(reg & DET_STA)) { - dev_dbg(dp->dev, "Input stream clock not detected.\n"); - return -EINVAL; - } - - reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2); - writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2); - - reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2); - dev_dbg(dp->dev, "wait SYS_CTL_2.\n"); - - if (reg & CHA_STA) { - dev_dbg(dp->dev, "Input stream clk is changing\n"); - return -EINVAL; - } - - return 0; -} - -void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp, - enum clock_recovery_m_value_type type, - u32 m_value, - u32 n_value) -{ - u32 reg; - - if (type == REGISTER_M) { - reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4); - reg |= FIX_M_VID; - writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4); - reg = m_value & 0xff; - writel(reg, dp->reg_base + EXYNOS_DP_M_VID_0); - reg = (m_value >> 8) & 0xff; - writel(reg, dp->reg_base + EXYNOS_DP_M_VID_1); - reg = (m_value >> 16) & 0xff; - writel(reg, dp->reg_base + EXYNOS_DP_M_VID_2); - - reg = n_value & 0xff; - writel(reg, dp->reg_base + EXYNOS_DP_N_VID_0); - reg = (n_value >> 8) & 0xff; - writel(reg, dp->reg_base + EXYNOS_DP_N_VID_1); - reg = (n_value >> 16) & 0xff; - writel(reg, dp->reg_base + EXYNOS_DP_N_VID_2); - } else { - reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4); - reg &= ~FIX_M_VID; - writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4); - - writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_0); - writel(0x80, dp->reg_base + EXYNOS_DP_N_VID_1); - writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_2); - } -} - -void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type) -{ - u32 reg; - - if (type == VIDEO_TIMING_FROM_CAPTURE) { - reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); - reg &= ~FORMAT_SEL; - writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); - } else { - reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); - reg |= FORMAT_SEL; - writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); - } -} - -void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable) -{ - u32 reg; - - if (enable) { - reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); - reg &= ~VIDEO_MODE_MASK; - reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE; - writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); - } else { - reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); - reg &= ~VIDEO_MODE_MASK; - reg |= VIDEO_MODE_SLAVE_MODE; - writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); - } -} - -void exynos_dp_start_video(struct exynos_dp_device *dp) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); - reg |= VIDEO_EN; - writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); -} - -int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); - writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3); - - reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); - if (!(reg & STRM_VALID)) { - dev_dbg(dp->dev, "Input video stream is not detected.\n"); - return -EINVAL; - } - - return 0; -} - -void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1); - reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N); - reg |= MASTER_VID_FUNC_EN_N; - writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1); - - reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); - reg &= ~INTERACE_SCAN_CFG; - reg |= (dp->video_info->interlaced << 2); - writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); - - reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); - reg &= ~VSYNC_POLARITY_CFG; - reg |= (dp->video_info->v_sync_polarity << 1); - writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); - - reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); - reg &= ~HSYNC_POLARITY_CFG; - reg |= (dp->video_info->h_sync_polarity << 0); - writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); - - reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE; - writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); -} - -void exynos_dp_enable_scrambling(struct exynos_dp_device *dp) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); - reg &= ~SCRAMBLING_DISABLE; - writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); -} - -void exynos_dp_disable_scrambling(struct exynos_dp_device *dp) -{ - u32 reg; - - reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); - reg |= SCRAMBLING_DISABLE; - writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); -} diff --git a/drivers/video/exynos/exynos_dp_reg.h b/drivers/video/exynos/exynos_dp_reg.h deleted file mode 100644 index 2e9bd0e0b9f2..000000000000 --- a/drivers/video/exynos/exynos_dp_reg.h +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Register definition file for Samsung DP driver - * - * Copyright (C) 2012 Samsung Electronics Co., Ltd. - * Author: Jingoo Han <jg1.han@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _EXYNOS_DP_REG_H -#define _EXYNOS_DP_REG_H - -#define EXYNOS_DP_TX_SW_RESET 0x14 -#define EXYNOS_DP_FUNC_EN_1 0x18 -#define EXYNOS_DP_FUNC_EN_2 0x1C -#define EXYNOS_DP_VIDEO_CTL_1 0x20 -#define EXYNOS_DP_VIDEO_CTL_2 0x24 -#define EXYNOS_DP_VIDEO_CTL_3 0x28 - -#define EXYNOS_DP_VIDEO_CTL_8 0x3C -#define EXYNOS_DP_VIDEO_CTL_10 0x44 - -#define EXYNOS_DP_LANE_MAP 0x35C - -#define EXYNOS_DP_ANALOG_CTL_1 0x370 -#define EXYNOS_DP_ANALOG_CTL_2 0x374 -#define EXYNOS_DP_ANALOG_CTL_3 0x378 -#define EXYNOS_DP_PLL_FILTER_CTL_1 0x37C -#define EXYNOS_DP_TX_AMP_TUNING_CTL 0x380 - -#define EXYNOS_DP_AUX_HW_RETRY_CTL 0x390 - -#define EXYNOS_DP_COMMON_INT_STA_1 0x3C4 -#define EXYNOS_DP_COMMON_INT_STA_2 0x3C8 -#define EXYNOS_DP_COMMON_INT_STA_3 0x3CC -#define EXYNOS_DP_COMMON_INT_STA_4 0x3D0 -#define EXYNOS_DP_INT_STA 0x3DC -#define EXYNOS_DP_COMMON_INT_MASK_1 0x3E0 -#define EXYNOS_DP_COMMON_INT_MASK_2 0x3E4 -#define EXYNOS_DP_COMMON_INT_MASK_3 0x3E8 -#define EXYNOS_DP_COMMON_INT_MASK_4 0x3EC -#define EXYNOS_DP_INT_STA_MASK 0x3F8 -#define EXYNOS_DP_INT_CTL 0x3FC - -#define EXYNOS_DP_SYS_CTL_1 0x600 -#define EXYNOS_DP_SYS_CTL_2 0x604 -#define EXYNOS_DP_SYS_CTL_3 0x608 -#define EXYNOS_DP_SYS_CTL_4 0x60C - -#define EXYNOS_DP_PKT_SEND_CTL 0x640 -#define EXYNOS_DP_HDCP_CTL 0x648 - -#define EXYNOS_DP_LINK_BW_SET 0x680 -#define EXYNOS_DP_LANE_COUNT_SET 0x684 -#define EXYNOS_DP_TRAINING_PTN_SET 0x688 -#define EXYNOS_DP_LN0_LINK_TRAINING_CTL 0x68C -#define EXYNOS_DP_LN1_LINK_TRAINING_CTL 0x690 -#define EXYNOS_DP_LN2_LINK_TRAINING_CTL 0x694 -#define EXYNOS_DP_LN3_LINK_TRAINING_CTL 0x698 - -#define EXYNOS_DP_DEBUG_CTL 0x6C0 -#define EXYNOS_DP_HPD_DEGLITCH_L 0x6C4 -#define EXYNOS_DP_HPD_DEGLITCH_H 0x6C8 -#define EXYNOS_DP_LINK_DEBUG_CTL 0x6E0 - -#define EXYNOS_DP_M_VID_0 0x700 -#define EXYNOS_DP_M_VID_1 0x704 -#define EXYNOS_DP_M_VID_2 0x708 -#define EXYNOS_DP_N_VID_0 0x70C -#define EXYNOS_DP_N_VID_1 0x710 -#define EXYNOS_DP_N_VID_2 0x714 - -#define EXYNOS_DP_PLL_CTL 0x71C -#define EXYNOS_DP_PHY_PD 0x720 -#define EXYNOS_DP_PHY_TEST 0x724 - -#define EXYNOS_DP_VIDEO_FIFO_THRD 0x730 -#define EXYNOS_DP_AUDIO_MARGIN 0x73C - -#define EXYNOS_DP_M_VID_GEN_FILTER_TH 0x764 -#define EXYNOS_DP_M_AUD_GEN_FILTER_TH 0x778 -#define EXYNOS_DP_AUX_CH_STA 0x780 -#define EXYNOS_DP_AUX_CH_DEFER_CTL 0x788 -#define EXYNOS_DP_AUX_RX_COMM 0x78C -#define EXYNOS_DP_BUFFER_DATA_CTL 0x790 -#define EXYNOS_DP_AUX_CH_CTL_1 0x794 -#define EXYNOS_DP_AUX_ADDR_7_0 0x798 -#define EXYNOS_DP_AUX_ADDR_15_8 0x79C -#define EXYNOS_DP_AUX_ADDR_19_16 0x7A0 -#define EXYNOS_DP_AUX_CH_CTL_2 0x7A4 - -#define EXYNOS_DP_BUF_DATA_0 0x7C0 - -#define EXYNOS_DP_SOC_GENERAL_CTL 0x800 - -/* EXYNOS_DP_TX_SW_RESET */ -#define RESET_DP_TX (0x1 << 0) - -/* EXYNOS_DP_FUNC_EN_1 */ -#define MASTER_VID_FUNC_EN_N (0x1 << 7) -#define SLAVE_VID_FUNC_EN_N (0x1 << 5) -#define AUD_FIFO_FUNC_EN_N (0x1 << 4) -#define AUD_FUNC_EN_N (0x1 << 3) -#define HDCP_FUNC_EN_N (0x1 << 2) -#define CRC_FUNC_EN_N (0x1 << 1) -#define SW_FUNC_EN_N (0x1 << 0) - -/* EXYNOS_DP_FUNC_EN_2 */ -#define SSC_FUNC_EN_N (0x1 << 7) -#define AUX_FUNC_EN_N (0x1 << 2) -#define SERDES_FIFO_FUNC_EN_N (0x1 << 1) -#define LS_CLK_DOMAIN_FUNC_EN_N (0x1 << 0) - -/* EXYNOS_DP_VIDEO_CTL_1 */ -#define VIDEO_EN (0x1 << 7) -#define HDCP_VIDEO_MUTE (0x1 << 6) - -/* EXYNOS_DP_VIDEO_CTL_1 */ -#define IN_D_RANGE_MASK (0x1 << 7) -#define IN_D_RANGE_SHIFT (7) -#define IN_D_RANGE_CEA (0x1 << 7) -#define IN_D_RANGE_VESA (0x0 << 7) -#define IN_BPC_MASK (0x7 << 4) -#define IN_BPC_SHIFT (4) -#define IN_BPC_12_BITS (0x3 << 4) -#define IN_BPC_10_BITS (0x2 << 4) -#define IN_BPC_8_BITS (0x1 << 4) -#define IN_BPC_6_BITS (0x0 << 4) -#define IN_COLOR_F_MASK (0x3 << 0) -#define IN_COLOR_F_SHIFT (0) -#define IN_COLOR_F_YCBCR444 (0x2 << 0) -#define IN_COLOR_F_YCBCR422 (0x1 << 0) -#define IN_COLOR_F_RGB (0x0 << 0) - -/* EXYNOS_DP_VIDEO_CTL_3 */ -#define IN_YC_COEFFI_MASK (0x1 << 7) -#define IN_YC_COEFFI_SHIFT (7) -#define IN_YC_COEFFI_ITU709 (0x1 << 7) -#define IN_YC_COEFFI_ITU601 (0x0 << 7) -#define VID_CHK_UPDATE_TYPE_MASK (0x1 << 4) -#define VID_CHK_UPDATE_TYPE_SHIFT (4) -#define VID_CHK_UPDATE_TYPE_1 (0x1 << 4) -#define VID_CHK_UPDATE_TYPE_0 (0x0 << 4) - -/* EXYNOS_DP_VIDEO_CTL_8 */ -#define VID_HRES_TH(x) (((x) & 0xf) << 4) -#define VID_VRES_TH(x) (((x) & 0xf) << 0) - -/* EXYNOS_DP_VIDEO_CTL_10 */ -#define FORMAT_SEL (0x1 << 4) -#define INTERACE_SCAN_CFG (0x1 << 2) -#define VSYNC_POLARITY_CFG (0x1 << 1) -#define HSYNC_POLARITY_CFG (0x1 << 0) - -/* EXYNOS_DP_LANE_MAP */ -#define LANE3_MAP_LOGIC_LANE_0 (0x0 << 6) -#define LANE3_MAP_LOGIC_LANE_1 (0x1 << 6) -#define LANE3_MAP_LOGIC_LANE_2 (0x2 << 6) -#define LANE3_MAP_LOGIC_LANE_3 (0x3 << 6) -#define LANE2_MAP_LOGIC_LANE_0 (0x0 << 4) -#define LANE2_MAP_LOGIC_LANE_1 (0x1 << 4) -#define LANE2_MAP_LOGIC_LANE_2 (0x2 << 4) -#define LANE2_MAP_LOGIC_LANE_3 (0x3 << 4) -#define LANE1_MAP_LOGIC_LANE_0 (0x0 << 2) -#define LANE1_MAP_LOGIC_LANE_1 (0x1 << 2) -#define LANE1_MAP_LOGIC_LANE_2 (0x2 << 2) -#define LANE1_MAP_LOGIC_LANE_3 (0x3 << 2) -#define LANE0_MAP_LOGIC_LANE_0 (0x0 << 0) -#define LANE0_MAP_LOGIC_LANE_1 (0x1 << 0) -#define LANE0_MAP_LOGIC_LANE_2 (0x2 << 0) -#define LANE0_MAP_LOGIC_LANE_3 (0x3 << 0) - -/* EXYNOS_DP_ANALOG_CTL_1 */ -#define TX_TERMINAL_CTRL_50_OHM (0x1 << 4) - -/* EXYNOS_DP_ANALOG_CTL_2 */ -#define SEL_24M (0x1 << 3) -#define TX_DVDD_BIT_1_0625V (0x4 << 0) - -/* EXYNOS_DP_ANALOG_CTL_3 */ -#define DRIVE_DVDD_BIT_1_0625V (0x4 << 5) -#define VCO_BIT_600_MICRO (0x5 << 0) - -/* EXYNOS_DP_PLL_FILTER_CTL_1 */ -#define PD_RING_OSC (0x1 << 6) -#define AUX_TERMINAL_CTRL_50_OHM (0x2 << 4) -#define TX_CUR1_2X (0x1 << 2) -#define TX_CUR_16_MA (0x3 << 0) - -/* EXYNOS_DP_TX_AMP_TUNING_CTL */ -#define CH3_AMP_400_MV (0x0 << 24) -#define CH2_AMP_400_MV (0x0 << 16) -#define CH1_AMP_400_MV (0x0 << 8) -#define CH0_AMP_400_MV (0x0 << 0) - -/* EXYNOS_DP_AUX_HW_RETRY_CTL */ -#define AUX_BIT_PERIOD_EXPECTED_DELAY(x) (((x) & 0x7) << 8) -#define AUX_HW_RETRY_INTERVAL_MASK (0x3 << 3) -#define AUX_HW_RETRY_INTERVAL_600_MICROSECONDS (0x0 << 3) -#define AUX_HW_RETRY_INTERVAL_800_MICROSECONDS (0x1 << 3) -#define AUX_HW_RETRY_INTERVAL_1000_MICROSECONDS (0x2 << 3) -#define AUX_HW_RETRY_INTERVAL_1800_MICROSECONDS (0x3 << 3) -#define AUX_HW_RETRY_COUNT_SEL(x) (((x) & 0x7) << 0) - -/* EXYNOS_DP_COMMON_INT_STA_1 */ -#define VSYNC_DET (0x1 << 7) -#define PLL_LOCK_CHG (0x1 << 6) -#define SPDIF_ERR (0x1 << 5) -#define SPDIF_UNSTBL (0x1 << 4) -#define VID_FORMAT_CHG (0x1 << 3) -#define AUD_CLK_CHG (0x1 << 2) -#define VID_CLK_CHG (0x1 << 1) -#define SW_INT (0x1 << 0) - -/* EXYNOS_DP_COMMON_INT_STA_2 */ -#define ENC_EN_CHG (0x1 << 6) -#define HW_BKSV_RDY (0x1 << 3) -#define HW_SHA_DONE (0x1 << 2) -#define HW_AUTH_STATE_CHG (0x1 << 1) -#define HW_AUTH_DONE (0x1 << 0) - -/* EXYNOS_DP_COMMON_INT_STA_3 */ -#define AFIFO_UNDER (0x1 << 7) -#define AFIFO_OVER (0x1 << 6) -#define R0_CHK_FLAG (0x1 << 5) - -/* EXYNOS_DP_COMMON_INT_STA_4 */ -#define PSR_ACTIVE (0x1 << 7) -#define PSR_INACTIVE (0x1 << 6) -#define SPDIF_BI_PHASE_ERR (0x1 << 5) -#define HOTPLUG_CHG (0x1 << 2) -#define HPD_LOST (0x1 << 1) -#define PLUG (0x1 << 0) - -/* EXYNOS_DP_INT_STA */ -#define INT_HPD (0x1 << 6) -#define HW_TRAINING_FINISH (0x1 << 5) -#define RPLY_RECEIV (0x1 << 1) -#define AUX_ERR (0x1 << 0) - -/* EXYNOS_DP_INT_CTL */ -#define SOFT_INT_CTRL (0x1 << 2) -#define INT_POL1 (0x1 << 1) -#define INT_POL0 (0x1 << 0) - -/* EXYNOS_DP_SYS_CTL_1 */ -#define DET_STA (0x1 << 2) -#define FORCE_DET (0x1 << 1) -#define DET_CTRL (0x1 << 0) - -/* EXYNOS_DP_SYS_CTL_2 */ -#define CHA_CRI(x) (((x) & 0xf) << 4) -#define CHA_STA (0x1 << 2) -#define FORCE_CHA (0x1 << 1) -#define CHA_CTRL (0x1 << 0) - -/* EXYNOS_DP_SYS_CTL_3 */ -#define HPD_STATUS (0x1 << 6) -#define F_HPD (0x1 << 5) -#define HPD_CTRL (0x1 << 4) -#define HDCP_RDY (0x1 << 3) -#define STRM_VALID (0x1 << 2) -#define F_VALID (0x1 << 1) -#define VALID_CTRL (0x1 << 0) - -/* EXYNOS_DP_SYS_CTL_4 */ -#define FIX_M_AUD (0x1 << 4) -#define ENHANCED (0x1 << 3) -#define FIX_M_VID (0x1 << 2) -#define M_VID_UPDATE_CTRL (0x3 << 0) - -/* EXYNOS_DP_TRAINING_PTN_SET */ -#define SCRAMBLER_TYPE (0x1 << 9) -#define HW_LINK_TRAINING_PATTERN (0x1 << 8) -#define SCRAMBLING_DISABLE (0x1 << 5) -#define SCRAMBLING_ENABLE (0x0 << 5) -#define LINK_QUAL_PATTERN_SET_MASK (0x3 << 2) -#define LINK_QUAL_PATTERN_SET_PRBS7 (0x3 << 2) -#define LINK_QUAL_PATTERN_SET_D10_2 (0x1 << 2) -#define LINK_QUAL_PATTERN_SET_DISABLE (0x0 << 2) -#define SW_TRAINING_PATTERN_SET_MASK (0x3 << 0) -#define SW_TRAINING_PATTERN_SET_PTN2 (0x2 << 0) -#define SW_TRAINING_PATTERN_SET_PTN1 (0x1 << 0) -#define SW_TRAINING_PATTERN_SET_NORMAL (0x0 << 0) - -/* EXYNOS_DP_LN0_LINK_TRAINING_CTL */ -#define PRE_EMPHASIS_SET_MASK (0x3 << 3) -#define PRE_EMPHASIS_SET_SHIFT (3) - -/* EXYNOS_DP_DEBUG_CTL */ -#define PLL_LOCK (0x1 << 4) -#define F_PLL_LOCK (0x1 << 3) -#define PLL_LOCK_CTRL (0x1 << 2) -#define PN_INV (0x1 << 0) - -/* EXYNOS_DP_PLL_CTL */ -#define DP_PLL_PD (0x1 << 7) -#define DP_PLL_RESET (0x1 << 6) -#define DP_PLL_LOOP_BIT_DEFAULT (0x1 << 4) -#define DP_PLL_REF_BIT_1_1250V (0x5 << 0) -#define DP_PLL_REF_BIT_1_2500V (0x7 << 0) - -/* EXYNOS_DP_PHY_PD */ -#define DP_PHY_PD (0x1 << 5) -#define AUX_PD (0x1 << 4) -#define CH3_PD (0x1 << 3) -#define CH2_PD (0x1 << 2) -#define CH1_PD (0x1 << 1) -#define CH0_PD (0x1 << 0) - -/* EXYNOS_DP_PHY_TEST */ -#define MACRO_RST (0x1 << 5) -#define CH1_TEST (0x1 << 1) -#define CH0_TEST (0x1 << 0) - -/* EXYNOS_DP_AUX_CH_STA */ -#define AUX_BUSY (0x1 << 4) -#define AUX_STATUS_MASK (0xf << 0) - -/* EXYNOS_DP_AUX_CH_DEFER_CTL */ -#define DEFER_CTRL_EN (0x1 << 7) -#define DEFER_COUNT(x) (((x) & 0x7f) << 0) - -/* EXYNOS_DP_AUX_RX_COMM */ -#define AUX_RX_COMM_I2C_DEFER (0x2 << 2) -#define AUX_RX_COMM_AUX_DEFER (0x2 << 0) - -/* EXYNOS_DP_BUFFER_DATA_CTL */ -#define BUF_CLR (0x1 << 7) -#define BUF_DATA_COUNT(x) (((x) & 0x1f) << 0) - -/* EXYNOS_DP_AUX_CH_CTL_1 */ -#define AUX_LENGTH(x) (((x - 1) & 0xf) << 4) -#define AUX_TX_COMM_MASK (0xf << 0) -#define AUX_TX_COMM_DP_TRANSACTION (0x1 << 3) -#define AUX_TX_COMM_I2C_TRANSACTION (0x0 << 3) -#define AUX_TX_COMM_MOT (0x1 << 2) -#define AUX_TX_COMM_WRITE (0x0 << 0) -#define AUX_TX_COMM_READ (0x1 << 0) - -/* EXYNOS_DP_AUX_ADDR_7_0 */ -#define AUX_ADDR_7_0(x) (((x) >> 0) & 0xff) - -/* EXYNOS_DP_AUX_ADDR_15_8 */ -#define AUX_ADDR_15_8(x) (((x) >> 8) & 0xff) - -/* EXYNOS_DP_AUX_ADDR_19_16 */ -#define AUX_ADDR_19_16(x) (((x) >> 16) & 0x0f) - -/* EXYNOS_DP_AUX_CH_CTL_2 */ -#define ADDR_ONLY (0x1 << 1) -#define AUX_EN (0x1 << 0) - -/* EXYNOS_DP_SOC_GENERAL_CTL */ -#define AUDIO_MODE_SPDIF_MODE (0x1 << 8) -#define AUDIO_MODE_MASTER_MODE (0x0 << 8) -#define MASTER_VIDEO_INTERLACE_EN (0x1 << 4) -#define VIDEO_MASTER_CLK_SEL (0x1 << 2) -#define VIDEO_MASTER_MODE_EN (0x1 << 1) -#define VIDEO_MODE_MASK (0x1 << 0) -#define VIDEO_MODE_SLAVE_MODE (0x1 << 0) -#define VIDEO_MODE_MASTER_MODE (0x0 << 0) - -#endif /* _EXYNOS_DP_REG_H */ diff --git a/drivers/video/exynos/s6e8ax0.c b/drivers/video/exynos/s6e8ax0.c index ca2602413aa4..29e70ed3f154 100644 --- a/drivers/video/exynos/s6e8ax0.c +++ b/drivers/video/exynos/s6e8ax0.c @@ -794,19 +794,18 @@ static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev) return ret; } - lcd->ld = lcd_device_register("s6e8ax0", lcd->dev, lcd, + lcd->ld = devm_lcd_device_register(lcd->dev, "s6e8ax0", lcd->dev, lcd, &s6e8ax0_lcd_ops); if (IS_ERR(lcd->ld)) { dev_err(lcd->dev, "failed to register lcd ops.\n"); return PTR_ERR(lcd->ld); } - lcd->bd = backlight_device_register("s6e8ax0-bl", lcd->dev, lcd, - &s6e8ax0_backlight_ops, NULL); + lcd->bd = devm_backlight_device_register(lcd->dev, "s6e8ax0-bl", + lcd->dev, lcd, &s6e8ax0_backlight_ops, NULL); if (IS_ERR(lcd->bd)) { dev_err(lcd->dev, "failed to register backlight ops.\n"); - ret = PTR_ERR(lcd->bd); - goto err_backlight_register; + return PTR_ERR(lcd->bd); } lcd->bd->props.max_brightness = MAX_BRIGHTNESS; @@ -834,10 +833,6 @@ static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev) dev_dbg(lcd->dev, "probed s6e8ax0 panel driver.\n"); return 0; - -err_backlight_register: - lcd_device_unregister(lcd->ld); - return ret; } #ifdef CONFIG_PM diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 7309ac704e26..b6d5008f361f 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1596,8 +1596,7 @@ static int do_remove_conflicting_framebuffers(struct apertures_struct *a, (primary && gen_aper && gen_aper->count && gen_aper->ranges[0].base == VGA_FB_PHYS)) { - printk(KERN_INFO "fb: conflicting fb hw usage " - "%s vs %s - removing generic driver\n", + printk(KERN_INFO "fb: switching to %s from %s\n", name, registered_fb[i]->fix.id); ret = do_unregister_framebuffer(registered_fb[i]); if (ret) diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index 4c7cb368a9dc..3ec65a878ac8 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c @@ -45,10 +45,6 @@ struct gbefb_par { #define GBE_BASE 0x16000000 /* SGI O2 */ #endif -#ifdef CONFIG_X86_VISWS -#define GBE_BASE 0xd0000000 /* SGI Visual Workstation */ -#endif - /* macro for fastest write-though access to the framebuffer */ #ifdef CONFIG_MIPS #ifdef CONFIG_CPU_R10000 diff --git a/drivers/video/hyperv_fb.c b/drivers/video/hyperv_fb.c index 130708f96430..e23392ec5af3 100644 --- a/drivers/video/hyperv_fb.c +++ b/drivers/video/hyperv_fb.c @@ -42,6 +42,7 @@ #include <linux/completion.h> #include <linux/fb.h> #include <linux/pci.h> +#include <linux/efi.h> #include <linux/hyperv.h> @@ -212,6 +213,7 @@ struct synthvid_msg { struct hvfb_par { struct fb_info *info; + struct resource mem; bool fb_ready; /* fb device is ready */ struct completion wait; u32 synthvid_version; @@ -460,13 +462,13 @@ static int synthvid_connect_vsp(struct hv_device *hdev) goto error; } - if (par->synthvid_version == SYNTHVID_VERSION_WIN7) { + if (par->synthvid_version == SYNTHVID_VERSION_WIN7) screen_depth = SYNTHVID_DEPTH_WIN7; - screen_fb_size = SYNTHVID_FB_SIZE_WIN7; - } else { + else screen_depth = SYNTHVID_DEPTH_WIN8; - screen_fb_size = SYNTHVID_FB_SIZE_WIN8; - } + + screen_fb_size = hdev->channel->offermsg.offer. + mmio_megabytes * 1024 * 1024; return 0; @@ -627,26 +629,46 @@ static void hvfb_get_option(struct fb_info *info) /* Get framebuffer memory from Hyper-V video pci space */ static int hvfb_getmem(struct fb_info *info) { - struct pci_dev *pdev; - ulong fb_phys; + struct hvfb_par *par = info->par; + struct pci_dev *pdev = NULL; void __iomem *fb_virt; + int gen2vm = efi_enabled(EFI_BOOT); + int ret; - pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT, + par->mem.name = KBUILD_MODNAME; + par->mem.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (gen2vm) { + ret = allocate_resource(&hyperv_mmio, &par->mem, + screen_fb_size, + 0, -1, + screen_fb_size, + NULL, NULL); + if (ret != 0) { + pr_err("Unable to allocate framebuffer memory\n"); + return -ENODEV; + } + } else { + pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT, PCI_DEVICE_ID_HYPERV_VIDEO, NULL); - if (!pdev) { - pr_err("Unable to find PCI Hyper-V video\n"); - return -ENODEV; - } + if (!pdev) { + pr_err("Unable to find PCI Hyper-V video\n"); + return -ENODEV; + } - if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) || - pci_resource_len(pdev, 0) < screen_fb_size) - goto err1; + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) || + pci_resource_len(pdev, 0) < screen_fb_size) + goto err1; - fb_phys = pci_resource_end(pdev, 0) - screen_fb_size + 1; - if (!request_mem_region(fb_phys, screen_fb_size, KBUILD_MODNAME)) - goto err1; + par->mem.end = pci_resource_end(pdev, 0); + par->mem.start = par->mem.end - screen_fb_size + 1; + ret = request_resource(&pdev->resource[0], &par->mem); + if (ret != 0) { + pr_err("Unable to request framebuffer memory\n"); + goto err1; + } + } - fb_virt = ioremap(fb_phys, screen_fb_size); + fb_virt = ioremap(par->mem.start, screen_fb_size); if (!fb_virt) goto err2; @@ -654,30 +676,44 @@ static int hvfb_getmem(struct fb_info *info) if (!info->apertures) goto err3; - info->apertures->ranges[0].base = pci_resource_start(pdev, 0); - info->apertures->ranges[0].size = pci_resource_len(pdev, 0); - info->fix.smem_start = fb_phys; + if (gen2vm) { + info->apertures->ranges[0].base = screen_info.lfb_base; + info->apertures->ranges[0].size = screen_info.lfb_size; + remove_conflicting_framebuffers(info->apertures, + KBUILD_MODNAME, false); + } else { + info->apertures->ranges[0].base = pci_resource_start(pdev, 0); + info->apertures->ranges[0].size = pci_resource_len(pdev, 0); + } + + info->fix.smem_start = par->mem.start; info->fix.smem_len = screen_fb_size; info->screen_base = fb_virt; info->screen_size = screen_fb_size; - pci_dev_put(pdev); + if (!gen2vm) + pci_dev_put(pdev); + return 0; err3: iounmap(fb_virt); err2: - release_mem_region(fb_phys, screen_fb_size); + release_resource(&par->mem); err1: - pci_dev_put(pdev); + if (!gen2vm) + pci_dev_put(pdev); + return -ENOMEM; } /* Release the framebuffer */ static void hvfb_putmem(struct fb_info *info) { + struct hvfb_par *par = info->par; + iounmap(info->screen_base); - release_mem_region(info->fix.smem_start, screen_fb_size); + release_resource(&par->mem); } diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 44ee678481d5..f6e621684953 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -30,10 +30,13 @@ #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/io.h> +#include <linux/lcd.h> #include <linux/math64.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/regulator/consumer.h> + #include <video/of_display_timing.h> #include <video/of_videomode.h> #include <video/videomode.h> @@ -45,12 +48,6 @@ */ #define DEBUG_VAR 1 -#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || \ - (defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) && \ - defined(CONFIG_FB_IMX_MODULE)) -#define PWMR_BACKLIGHT_AVAILABLE -#endif - #define DRIVER_NAME "imx-fb" #define LCDC_SSA 0x00 @@ -153,11 +150,8 @@ struct imxfb_info { * the framebuffer memory region to. */ dma_addr_t map_dma; - u_char *map_cpu; u_int map_size; - u_char *screen_cpu; - dma_addr_t screen_dma; u_int palette_size; dma_addr_t dbar1; @@ -167,18 +161,13 @@ struct imxfb_info { u_int pwmr; u_int lscr1; u_int dmacr; - u_int cmap_inverse:1, - cmap_static:1, - unused:30; + bool cmap_inverse; + bool cmap_static; struct imx_fb_videomode *mode; int num_modes; -#ifdef PWMR_BACKLIGHT_AVAILABLE - struct backlight_device *bl; -#endif - void (*lcd_power)(int); - void (*backlight_power)(int); + struct regulator *lcd_pwr; }; static struct platform_device_id imxfb_devtype[] = { @@ -484,83 +473,6 @@ static int imxfb_set_par(struct fb_info *info) return 0; } -#ifdef PWMR_BACKLIGHT_AVAILABLE -static int imxfb_bl_get_brightness(struct backlight_device *bl) -{ - struct imxfb_info *fbi = bl_get_data(bl); - - return readl(fbi->regs + LCDC_PWMR) & 0xFF; -} - -static int imxfb_bl_update_status(struct backlight_device *bl) -{ - struct imxfb_info *fbi = bl_get_data(bl); - int brightness = bl->props.brightness; - - if (!fbi->pwmr) - return 0; - - if (bl->props.power != FB_BLANK_UNBLANK) - brightness = 0; - if (bl->props.fb_blank != FB_BLANK_UNBLANK) - brightness = 0; - - fbi->pwmr = (fbi->pwmr & ~0xFF) | brightness; - - if (bl->props.fb_blank != FB_BLANK_UNBLANK) { - clk_prepare_enable(fbi->clk_ipg); - clk_prepare_enable(fbi->clk_ahb); - clk_prepare_enable(fbi->clk_per); - } - writel(fbi->pwmr, fbi->regs + LCDC_PWMR); - if (bl->props.fb_blank != FB_BLANK_UNBLANK) { - clk_disable_unprepare(fbi->clk_per); - clk_disable_unprepare(fbi->clk_ahb); - clk_disable_unprepare(fbi->clk_ipg); - } - - return 0; -} - -static const struct backlight_ops imxfb_lcdc_bl_ops = { - .update_status = imxfb_bl_update_status, - .get_brightness = imxfb_bl_get_brightness, -}; - -static void imxfb_init_backlight(struct imxfb_info *fbi) -{ - struct backlight_properties props; - struct backlight_device *bl; - - if (fbi->bl) - return; - - memset(&props, 0, sizeof(struct backlight_properties)); - props.max_brightness = 0xff; - props.type = BACKLIGHT_RAW; - writel(fbi->pwmr, fbi->regs + LCDC_PWMR); - - bl = backlight_device_register("imxfb-bl", &fbi->pdev->dev, fbi, - &imxfb_lcdc_bl_ops, &props); - if (IS_ERR(bl)) { - dev_err(&fbi->pdev->dev, "error %ld on backlight register\n", - PTR_ERR(bl)); - return; - } - - fbi->bl = bl; - bl->props.power = FB_BLANK_UNBLANK; - bl->props.fb_blank = FB_BLANK_UNBLANK; - bl->props.brightness = imxfb_bl_get_brightness(bl); -} - -static void imxfb_exit_backlight(struct imxfb_info *fbi) -{ - if (fbi->bl) - backlight_device_unregister(fbi->bl); -} -#endif - static void imxfb_enable_controller(struct imxfb_info *fbi) { @@ -569,7 +481,7 @@ static void imxfb_enable_controller(struct imxfb_info *fbi) pr_debug("Enabling LCD controller\n"); - writel(fbi->screen_dma, fbi->regs + LCDC_SSA); + writel(fbi->map_dma, fbi->regs + LCDC_SSA); /* panning offset 0 (0 pixel offset) */ writel(0x00000000, fbi->regs + LCDC_POS); @@ -588,11 +500,6 @@ static void imxfb_enable_controller(struct imxfb_info *fbi) clk_prepare_enable(fbi->clk_ahb); clk_prepare_enable(fbi->clk_per); fbi->enabled = true; - - if (fbi->backlight_power) - fbi->backlight_power(1); - if (fbi->lcd_power) - fbi->lcd_power(1); } static void imxfb_disable_controller(struct imxfb_info *fbi) @@ -602,11 +509,6 @@ static void imxfb_disable_controller(struct imxfb_info *fbi) pr_debug("Disabling LCD controller\n"); - if (fbi->backlight_power) - fbi->backlight_power(0); - if (fbi->lcd_power) - fbi->lcd_power(0); - clk_disable_unprepare(fbi->clk_per); clk_disable_unprepare(fbi->clk_ipg); clk_disable_unprepare(fbi->clk_ahb); @@ -709,10 +611,8 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf fbi->regs + LCDC_SIZE); writel(fbi->pcr, fbi->regs + LCDC_PCR); -#ifndef PWMR_BACKLIGHT_AVAILABLE if (fbi->pwmr) writel(fbi->pwmr, fbi->regs + LCDC_PWMR); -#endif writel(fbi->lscr1, fbi->regs + LCDC_LSCR1); /* dmacr = 0 is no valid value, as we need DMA control marks. */ @@ -722,37 +622,6 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf return 0; } -#ifdef CONFIG_PM -/* - * Power management hooks. Note that we won't be called from IRQ context, - * unlike the blank functions above, so we may sleep. - */ -static int imxfb_suspend(struct platform_device *dev, pm_message_t state) -{ - struct fb_info *info = platform_get_drvdata(dev); - struct imxfb_info *fbi = info->par; - - pr_debug("%s\n", __func__); - - imxfb_disable_controller(fbi); - return 0; -} - -static int imxfb_resume(struct platform_device *dev) -{ - struct fb_info *info = platform_get_drvdata(dev); - struct imxfb_info *fbi = info->par; - - pr_debug("%s\n", __func__); - - imxfb_enable_controller(fbi); - return 0; -} -#else -#define imxfb_suspend NULL -#define imxfb_resume NULL -#endif - static int imxfb_init_fbinfo(struct platform_device *pdev) { struct imx_fb_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -790,14 +659,9 @@ static int imxfb_init_fbinfo(struct platform_device *pdev) info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST; if (pdata) { - info->var.grayscale = pdata->cmap_greyscale; - fbi->cmap_inverse = pdata->cmap_inverse; - fbi->cmap_static = pdata->cmap_static; fbi->lscr1 = pdata->lscr1; fbi->dmacr = pdata->dmacr; fbi->pwmr = pdata->pwmr; - fbi->lcd_power = pdata->lcd_power; - fbi->backlight_power = pdata->backlight_power; } else { np = pdev->dev.of_node; info->var.grayscale = of_property_read_bool(np, @@ -806,14 +670,12 @@ static int imxfb_init_fbinfo(struct platform_device *pdev) fbi->cmap_static = of_property_read_bool(np, "cmap-static"); fbi->lscr1 = IMXFB_LSCR1_DEFAULT; + + of_property_read_u32(np, "fsl,lpccr", &fbi->pwmr); + of_property_read_u32(np, "fsl,lscr1", &fbi->lscr1); of_property_read_u32(np, "fsl,dmacr", &fbi->dmacr); - - /* These two function pointers could be used by some specific - * platforms. */ - fbi->lcd_power = NULL; - fbi->backlight_power = NULL; } return 0; @@ -856,9 +718,98 @@ static int imxfb_of_read_mode(struct device *dev, struct device_node *np, return 0; } +static int imxfb_lcd_check_fb(struct lcd_device *lcddev, struct fb_info *fi) +{ + struct imxfb_info *fbi = dev_get_drvdata(&lcddev->dev); + + if (!fi || fi->par == fbi) + return 1; + + return 0; +} + +static int imxfb_lcd_get_contrast(struct lcd_device *lcddev) +{ + struct imxfb_info *fbi = dev_get_drvdata(&lcddev->dev); + + return fbi->pwmr & 0xff; +} + +static int imxfb_lcd_set_contrast(struct lcd_device *lcddev, int contrast) +{ + struct imxfb_info *fbi = dev_get_drvdata(&lcddev->dev); + + if (fbi->pwmr && fbi->enabled) { + if (contrast > 255) + contrast = 255; + else if (contrast < 0) + contrast = 0; + + fbi->pwmr &= ~0xff; + fbi->pwmr |= contrast; + + writel(fbi->pwmr, fbi->regs + LCDC_PWMR); + } + + return 0; +} + +static int imxfb_lcd_get_power(struct lcd_device *lcddev) +{ + struct imxfb_info *fbi = dev_get_drvdata(&lcddev->dev); + + if (!IS_ERR(fbi->lcd_pwr)) + return regulator_is_enabled(fbi->lcd_pwr); + + return 1; +} + +static int imxfb_lcd_set_power(struct lcd_device *lcddev, int power) +{ + struct imxfb_info *fbi = dev_get_drvdata(&lcddev->dev); + + if (!IS_ERR(fbi->lcd_pwr)) { + if (power) + return regulator_enable(fbi->lcd_pwr); + else + return regulator_disable(fbi->lcd_pwr); + } + + return 0; +} + +static struct lcd_ops imxfb_lcd_ops = { + .check_fb = imxfb_lcd_check_fb, + .get_contrast = imxfb_lcd_get_contrast, + .set_contrast = imxfb_lcd_set_contrast, + .get_power = imxfb_lcd_get_power, + .set_power = imxfb_lcd_set_power, +}; + +static int imxfb_setup(void) +{ + char *opt, *options = NULL; + + if (fb_get_options("imxfb", &options)) + return -ENODEV; + + if (!options || !*options) + return 0; + + while ((opt = strsep(&options, ",")) != NULL) { + if (!*opt) + continue; + else + fb_mode = opt; + } + + return 0; +} + static int imxfb_probe(struct platform_device *pdev) { struct imxfb_info *fbi; + struct lcd_device *lcd; struct fb_info *info; struct imx_fb_platform_data *pdata; struct resource *res; @@ -869,6 +820,10 @@ static int imxfb_probe(struct platform_device *pdev) dev_info(&pdev->dev, "i.MX Framebuffer driver\n"); + ret = imxfb_setup(); + if (ret < 0) + return ret; + of_id = of_match_device(imxfb_of_dev_id, &pdev->dev); if (of_id) pdev->id_entry = of_id->data; @@ -966,32 +921,18 @@ static int imxfb_probe(struct platform_device *pdev) goto failed_ioremap; } - /* Seems not being used by anyone, so no support for oftree */ - if (!pdata || !pdata->fixed_screen_cpu) { - fbi->map_size = PAGE_ALIGN(info->fix.smem_len); - fbi->map_cpu = dma_alloc_writecombine(&pdev->dev, - fbi->map_size, &fbi->map_dma, GFP_KERNEL); + fbi->map_size = PAGE_ALIGN(info->fix.smem_len); + info->screen_base = dma_alloc_writecombine(&pdev->dev, fbi->map_size, + &fbi->map_dma, GFP_KERNEL); - if (!fbi->map_cpu) { - dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret); - ret = -ENOMEM; - goto failed_map; - } - - info->screen_base = fbi->map_cpu; - fbi->screen_cpu = fbi->map_cpu; - fbi->screen_dma = fbi->map_dma; - info->fix.smem_start = fbi->screen_dma; - } else { - /* Fixed framebuffer mapping enables location of the screen in eSRAM */ - fbi->map_cpu = pdata->fixed_screen_cpu; - fbi->map_dma = pdata->fixed_screen_dma; - info->screen_base = fbi->map_cpu; - fbi->screen_cpu = fbi->map_cpu; - fbi->screen_dma = fbi->map_dma; - info->fix.smem_start = fbi->screen_dma; + if (!info->screen_base) { + dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret); + ret = -ENOMEM; + goto failed_map; } + info->fix.smem_start = fbi->map_dma; + if (pdata && pdata->init) { ret = pdata->init(fbi->pdev); if (ret) @@ -1020,23 +961,37 @@ static int imxfb_probe(struct platform_device *pdev) goto failed_register; } + fbi->lcd_pwr = devm_regulator_get(&pdev->dev, "lcd"); + if (IS_ERR(fbi->lcd_pwr) && (PTR_ERR(fbi->lcd_pwr) == -EPROBE_DEFER)) { + ret = -EPROBE_DEFER; + goto failed_lcd; + } + + lcd = devm_lcd_device_register(&pdev->dev, "imxfb-lcd", &pdev->dev, fbi, + &imxfb_lcd_ops); + if (IS_ERR(lcd)) { + ret = PTR_ERR(lcd); + goto failed_lcd; + } + + lcd->props.max_contrast = 0xff; + imxfb_enable_controller(fbi); fbi->pdev = pdev; -#ifdef PWMR_BACKLIGHT_AVAILABLE - imxfb_init_backlight(fbi); -#endif return 0; +failed_lcd: + unregister_framebuffer(info); + failed_register: fb_dealloc_cmap(&info->cmap); failed_cmap: if (pdata && pdata->exit) pdata->exit(fbi->pdev); failed_platform_init: - if (pdata && !pdata->fixed_screen_cpu) - dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu, - fbi->map_dma); + dma_free_writecombine(&pdev->dev, fbi->map_size, info->screen_base, + fbi->map_dma); failed_map: iounmap(fbi->regs); failed_ioremap: @@ -1061,9 +1016,6 @@ static int imxfb_remove(struct platform_device *pdev) imxfb_disable_controller(fbi); -#ifdef PWMR_BACKLIGHT_AVAILABLE - imxfb_exit_backlight(fbi); -#endif unregister_framebuffer(info); pdata = dev_get_platdata(&pdev->dev); @@ -1074,69 +1026,49 @@ static int imxfb_remove(struct platform_device *pdev) kfree(info->pseudo_palette); framebuffer_release(info); + dma_free_writecombine(&pdev->dev, fbi->map_size, info->screen_base, + fbi->map_dma); + iounmap(fbi->regs); release_mem_region(res->start, resource_size(res)); return 0; } -static void imxfb_shutdown(struct platform_device *dev) +static int __maybe_unused imxfb_suspend(struct device *dev) { - struct fb_info *info = platform_get_drvdata(dev); + struct fb_info *info = dev_get_drvdata(dev); struct imxfb_info *fbi = info->par; - imxfb_disable_controller(fbi); -} - -static struct platform_driver imxfb_driver = { - .suspend = imxfb_suspend, - .resume = imxfb_resume, - .remove = imxfb_remove, - .shutdown = imxfb_shutdown, - .driver = { - .name = DRIVER_NAME, - .of_match_table = imxfb_of_dev_id, - }, - .id_table = imxfb_devtype, -}; - -static int imxfb_setup(void) -{ -#ifndef MODULE - char *opt, *options = NULL; - if (fb_get_options("imxfb", &options)) - return -ENODEV; - - if (!options || !*options) - return 0; + imxfb_disable_controller(fbi); - while ((opt = strsep(&options, ",")) != NULL) { - if (!*opt) - continue; - else - fb_mode = opt; - } -#endif return 0; } -static int __init imxfb_init(void) +static int __maybe_unused imxfb_resume(struct device *dev) { - int ret = imxfb_setup(); + struct fb_info *info = dev_get_drvdata(dev); + struct imxfb_info *fbi = info->par; - if (ret < 0) - return ret; + imxfb_enable_controller(fbi); - return platform_driver_probe(&imxfb_driver, imxfb_probe); + return 0; } -static void __exit imxfb_cleanup(void) -{ - platform_driver_unregister(&imxfb_driver); -} +static SIMPLE_DEV_PM_OPS(imxfb_pm_ops, imxfb_suspend, imxfb_resume); -module_init(imxfb_init); -module_exit(imxfb_cleanup); +static struct platform_driver imxfb_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = imxfb_of_dev_id, + .owner = THIS_MODULE, + .pm = &imxfb_pm_ops, + }, + .probe = imxfb_probe, + .remove = imxfb_remove, + .id_table = imxfb_devtype, +}; +module_platform_driver(imxfb_driver); MODULE_DESCRIPTION("Freescale i.MX framebuffer driver"); MODULE_AUTHOR("Sascha Hauer, Pengutronix"); diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig index 39ac49e0682c..0037104d66ac 100644 --- a/drivers/video/logo/Kconfig +++ b/drivers/video/logo/Kconfig @@ -54,7 +54,7 @@ config LOGO_PARISC_CLUT224 config LOGO_SGI_CLUT224 bool "224-color SGI Linux logo" - depends on SGI_IP22 || SGI_IP27 || SGI_IP32 || X86_VISWS + depends on SGI_IP22 || SGI_IP27 || SGI_IP32 default y config LOGO_SUN_CLUT224 diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c index b670cbda38e3..940cd196eef5 100644 --- a/drivers/video/logo/logo.c +++ b/drivers/video/logo/logo.c @@ -81,7 +81,7 @@ const struct linux_logo * __init_refok fb_find_logo(int depth) logo = &logo_parisc_clut224; #endif #ifdef CONFIG_LOGO_SGI_CLUT224 - /* SGI Linux logo on MIPS/MIPS64 and VISWS */ + /* SGI Linux logo on MIPS/MIPS64 */ logo = &logo_sgi_clut224; #endif #ifdef CONFIG_LOGO_SUN_CLUT224 diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c index 8335a6fe303e..0d5cb85d071a 100644 --- a/drivers/video/matrox/matroxfb_accel.c +++ b/drivers/video/matrox/matroxfb_accel.c @@ -192,10 +192,18 @@ void matrox_cfbX_init(struct matrox_fb_info *minfo) minfo->accel.m_dwg_rect = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO; if (isMilleniumII(minfo)) minfo->accel.m_dwg_rect |= M_DWG_TRANSC; minfo->accel.m_opmode = mopmode; + minfo->accel.m_access = maccess; + minfo->accel.m_pitch = mpitch; } EXPORT_SYMBOL(matrox_cfbX_init); +static void matrox_accel_restore_maccess(struct matrox_fb_info *minfo) +{ + mga_outl(M_MACCESS, minfo->accel.m_access); + mga_outl(M_PITCH, minfo->accel.m_pitch); +} + static void matrox_accel_bmove(struct matrox_fb_info *minfo, int vxres, int sy, int sx, int dy, int dx, int height, int width) { @@ -207,7 +215,8 @@ static void matrox_accel_bmove(struct matrox_fb_info *minfo, int vxres, int sy, CRITBEGIN if ((dy < sy) || ((dy == sy) && (dx <= sx))) { - mga_fifo(2); + mga_fifo(4); + matrox_accel_restore_maccess(minfo); mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO | M_DWG_BFCOL | M_DWG_REPLACE); mga_outl(M_AR5, vxres); @@ -215,7 +224,8 @@ static void matrox_accel_bmove(struct matrox_fb_info *minfo, int vxres, int sy, start = sy*vxres+sx+curr_ydstorg(minfo); end = start+width; } else { - mga_fifo(3); + mga_fifo(5); + matrox_accel_restore_maccess(minfo); mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE); mga_outl(M_SGN, 5); mga_outl(M_AR5, -vxres); @@ -224,7 +234,8 @@ static void matrox_accel_bmove(struct matrox_fb_info *minfo, int vxres, int sy, start = end+width; dy += height-1; } - mga_fifo(4); + mga_fifo(6); + matrox_accel_restore_maccess(minfo); mga_outl(M_AR0, end); mga_outl(M_AR3, start); mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx); @@ -246,7 +257,8 @@ static void matrox_accel_bmove_lin(struct matrox_fb_info *minfo, int vxres, CRITBEGIN if ((dy < sy) || ((dy == sy) && (dx <= sx))) { - mga_fifo(2); + mga_fifo(4); + matrox_accel_restore_maccess(minfo); mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO | M_DWG_BFCOL | M_DWG_REPLACE); mga_outl(M_AR5, vxres); @@ -254,7 +266,8 @@ static void matrox_accel_bmove_lin(struct matrox_fb_info *minfo, int vxres, start = sy*vxres+sx+curr_ydstorg(minfo); end = start+width; } else { - mga_fifo(3); + mga_fifo(5); + matrox_accel_restore_maccess(minfo); mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE); mga_outl(M_SGN, 5); mga_outl(M_AR5, -vxres); @@ -263,7 +276,8 @@ static void matrox_accel_bmove_lin(struct matrox_fb_info *minfo, int vxres, start = end+width; dy += height-1; } - mga_fifo(5); + mga_fifo(7); + matrox_accel_restore_maccess(minfo); mga_outl(M_AR0, end); mga_outl(M_AR3, start); mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx); @@ -298,7 +312,8 @@ static void matroxfb_accel_clear(struct matrox_fb_info *minfo, u_int32_t color, CRITBEGIN - mga_fifo(5); + mga_fifo(7); + matrox_accel_restore_maccess(minfo); mga_outl(M_DWGCTL, minfo->accel.m_dwg_rect | M_DWG_REPLACE); mga_outl(M_FCOL, color); mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx); @@ -341,7 +356,8 @@ static void matroxfb_cfb4_clear(struct matrox_fb_info *minfo, u_int32_t bgx, width >>= 1; sx >>= 1; if (width) { - mga_fifo(5); + mga_fifo(7); + matrox_accel_restore_maccess(minfo); mga_outl(M_DWGCTL, minfo->accel.m_dwg_rect | M_DWG_REPLACE2); mga_outl(M_FCOL, bgx); mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx); @@ -415,7 +431,8 @@ static void matroxfb_1bpp_imageblit(struct matrox_fb_info *minfo, u_int32_t fgx, CRITBEGIN - mga_fifo(3); + mga_fifo(5); + matrox_accel_restore_maccess(minfo); if (easy) mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); else @@ -425,7 +442,8 @@ static void matroxfb_1bpp_imageblit(struct matrox_fb_info *minfo, u_int32_t fgx, fxbndry = ((xx + width - 1) << 16) | xx; mmio = minfo->mmio.vbase; - mga_fifo(6); + mga_fifo(8); + matrox_accel_restore_maccess(minfo); mga_writel(mmio, M_FXBNDRY, fxbndry); mga_writel(mmio, M_AR0, ar0); mga_writel(mmio, M_AR3, 0); diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 87c64ff4546c..7116c5309c7d 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -1773,7 +1773,8 @@ static int initMatrox2(struct matrox_fb_info *minfo, struct board *b) FBINFO_HWACCEL_FILLRECT | /* And fillrect */ FBINFO_HWACCEL_IMAGEBLIT | /* And imageblit */ FBINFO_HWACCEL_XPAN | /* And we support both horizontal */ - FBINFO_HWACCEL_YPAN; /* And vertical panning */ + FBINFO_HWACCEL_YPAN | /* And vertical panning */ + FBINFO_READS_FAST; minfo->video.len_usable &= PAGE_MASK; fb_alloc_cmap(&minfo->fbcon.cmap, 256, 1); diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h index 11ed57bb704e..556d96ce40bf 100644 --- a/drivers/video/matrox/matroxfb_base.h +++ b/drivers/video/matrox/matroxfb_base.h @@ -307,6 +307,8 @@ struct matrox_accel_data { #endif u_int32_t m_dwg_rect; u_int32_t m_opmode; + u_int32_t m_access; + u_int32_t m_pitch; }; struct v4l2_queryctrl; diff --git a/drivers/video/omap2/displays-new/connector-analog-tv.c b/drivers/video/omap2/displays-new/connector-analog-tv.c index ccd9073f706f..5ee3b5505f7f 100644 --- a/drivers/video/omap2/displays-new/connector-analog-tv.c +++ b/drivers/video/omap2/displays-new/connector-analog-tv.c @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/of.h> #include <video/omapdss.h> #include <video/omap-panel-data.h> @@ -31,7 +32,7 @@ struct panel_drv_data { static const struct omap_video_timings tvc_pal_timings = { .x_res = 720, .y_res = 574, - .pixel_clock = 13500, + .pixelclock = 13500000, .hsw = 64, .hfp = 12, .hbp = 68, @@ -42,6 +43,12 @@ static const struct omap_video_timings tvc_pal_timings = { .interlace = true, }; +static const struct of_device_id tvc_of_match[]; + +struct tvc_of_data { + enum omap_dss_venc_type connector_type; +}; + #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) static int tvc_connect(struct omap_dss_device *dssdev) @@ -91,8 +98,12 @@ static int tvc_enable(struct omap_dss_device *dssdev) in->ops.atv->set_timings(in, &ddata->timings); - in->ops.atv->set_type(in, ddata->connector_type); - in->ops.atv->invert_vid_out_polarity(in, ddata->invert_polarity); + if (!ddata->dev->of_node) { + in->ops.atv->set_type(in, ddata->connector_type); + + in->ops.atv->invert_vid_out_polarity(in, + ddata->invert_polarity); + } r = in->ops.atv->enable(in); if (r) @@ -205,6 +216,23 @@ static int tvc_probe_pdata(struct platform_device *pdev) return 0; } +static int tvc_probe_of(struct platform_device *pdev) +{ + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + struct omap_dss_device *in; + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + return 0; +} + static int tvc_probe(struct platform_device *pdev) { struct panel_drv_data *ddata; @@ -222,6 +250,10 @@ static int tvc_probe(struct platform_device *pdev) r = tvc_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = tvc_probe_of(pdev); + if (r) + return r; } else { return -ENODEV; } @@ -263,12 +295,19 @@ static int __exit tvc_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id tvc_of_match[] = { + { .compatible = "omapdss,svideo-connector", }, + { .compatible = "omapdss,composite-video-connector", }, + {}, +}; + static struct platform_driver tvc_connector_driver = { .probe = tvc_probe, .remove = __exit_p(tvc_remove), .driver = { .name = "connector-analog-tv", .owner = THIS_MODULE, + .of_match_table = tvc_of_match, }, }; diff --git a/drivers/video/omap2/displays-new/connector-dvi.c b/drivers/video/omap2/displays-new/connector-dvi.c index b6c50904038e..74de2bc50c4f 100644 --- a/drivers/video/omap2/displays-new/connector-dvi.c +++ b/drivers/video/omap2/displays-new/connector-dvi.c @@ -23,7 +23,7 @@ static const struct omap_video_timings dvic_default_timings = { .x_res = 640, .y_res = 480, - .pixel_clock = 23500, + .pixelclock = 23500000, .hfp = 48, .hsw = 32, @@ -277,6 +277,37 @@ static int dvic_probe_pdata(struct platform_device *pdev) return 0; } +static int dvic_probe_of(struct platform_device *pdev) +{ + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + struct omap_dss_device *in; + struct device_node *adapter_node; + struct i2c_adapter *adapter; + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + adapter_node = of_parse_phandle(node, "ddc-i2c-bus", 0); + if (adapter_node) { + adapter = of_find_i2c_adapter_by_node(adapter_node); + if (adapter == NULL) { + dev_err(&pdev->dev, "failed to parse ddc-i2c-bus\n"); + omap_dss_put_device(ddata->in); + return -EPROBE_DEFER; + } + + ddata->i2c_adapter = adapter; + } + + return 0; +} + static int dvic_probe(struct platform_device *pdev) { struct panel_drv_data *ddata; @@ -293,6 +324,10 @@ static int dvic_probe(struct platform_device *pdev) r = dvic_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = dvic_probe_of(pdev); + if (r) + return r; } else { return -ENODEV; } @@ -342,12 +377,20 @@ static int __exit dvic_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id dvic_of_match[] = { + { .compatible = "omapdss,dvi-connector", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, dvic_of_match); + static struct platform_driver dvi_connector_driver = { .probe = dvic_probe, .remove = __exit_p(dvic_remove), .driver = { .name = "connector-dvi", .owner = THIS_MODULE, + .of_match_table = dvic_of_match, }, }; diff --git a/drivers/video/omap2/displays-new/connector-hdmi.c b/drivers/video/omap2/displays-new/connector-hdmi.c index 9abe2c039ae9..29ed21b9dce5 100644 --- a/drivers/video/omap2/displays-new/connector-hdmi.c +++ b/drivers/video/omap2/displays-new/connector-hdmi.c @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/of.h> #include <drm/drm_edid.h> @@ -21,7 +22,7 @@ static const struct omap_video_timings hdmic_default_timings = { .x_res = 640, .y_res = 480, - .pixel_clock = 25175, + .pixelclock = 25175000, .hsw = 96, .hfp = 16, .hbp = 48, @@ -301,6 +302,23 @@ static int hdmic_probe_pdata(struct platform_device *pdev) return 0; } +static int hdmic_probe_of(struct platform_device *pdev) +{ + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + struct omap_dss_device *in; + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + return 0; +} + static int hdmic_probe(struct platform_device *pdev) { struct panel_drv_data *ddata; @@ -318,6 +336,10 @@ static int hdmic_probe(struct platform_device *pdev) r = hdmic_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = hdmic_probe_of(pdev); + if (r) + return r; } else { return -ENODEV; } @@ -359,12 +381,20 @@ static int __exit hdmic_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id hdmic_of_match[] = { + { .compatible = "omapdss,hdmi-connector", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, hdmic_of_match); + static struct platform_driver hdmi_connector_driver = { .probe = hdmic_probe, .remove = __exit_p(hdmic_remove), .driver = { .name = "connector-hdmi", .owner = THIS_MODULE, + .of_match_table = hdmic_of_match, }, }; diff --git a/drivers/video/omap2/displays-new/encoder-tfp410.c b/drivers/video/omap2/displays-new/encoder-tfp410.c index 4a291e756be9..b4e9a42a79e6 100644 --- a/drivers/video/omap2/displays-new/encoder-tfp410.c +++ b/drivers/video/omap2/displays-new/encoder-tfp410.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/of_gpio.h> #include <video/omapdss.h> #include <video/omap-panel-data.h> @@ -82,7 +83,8 @@ static int tfp410_enable(struct omap_dss_device *dssdev) return 0; in->ops.dpi->set_timings(in, &ddata->timings); - in->ops.dpi->set_data_lines(in, ddata->data_lines); + if (ddata->data_lines) + in->ops.dpi->set_data_lines(in, ddata->data_lines); r = in->ops.dpi->enable(in); if (r) @@ -179,6 +181,33 @@ static int tfp410_probe_pdata(struct platform_device *pdev) return 0; } +static int tfp410_probe_of(struct platform_device *pdev) +{ + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + struct omap_dss_device *in; + int gpio; + + gpio = of_get_named_gpio(node, "powerdown-gpios", 0); + + if (gpio_is_valid(gpio) || gpio == -ENOENT) { + ddata->pd_gpio = gpio; + } else { + dev_err(&pdev->dev, "failed to parse PD gpio\n"); + return gpio; + } + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + return 0; +} + static int tfp410_probe(struct platform_device *pdev) { struct panel_drv_data *ddata; @@ -195,6 +224,10 @@ static int tfp410_probe(struct platform_device *pdev) r = tfp410_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = tfp410_probe_of(pdev); + if (r) + return r; } else { return -ENODEV; } @@ -251,12 +284,20 @@ static int __exit tfp410_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id tfp410_of_match[] = { + { .compatible = "omapdss,ti,tfp410", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, tfp410_of_match); + static struct platform_driver tfp410_driver = { .probe = tfp410_probe, .remove = __exit_p(tfp410_remove), .driver = { .name = "tfp410", .owner = THIS_MODULE, + .of_match_table = tfp410_of_match, }, }; diff --git a/drivers/video/omap2/displays-new/encoder-tpd12s015.c b/drivers/video/omap2/displays-new/encoder-tpd12s015.c index d5c936cb217f..7e33686171e3 100644 --- a/drivers/video/omap2/displays-new/encoder-tpd12s015.c +++ b/drivers/video/omap2/displays-new/encoder-tpd12s015.c @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <linux/gpio.h> #include <linux/platform_device.h> +#include <linux/of_gpio.h> #include <video/omapdss.h> #include <video/omap-panel-data.h> @@ -289,6 +290,49 @@ static int tpd_probe_pdata(struct platform_device *pdev) return 0; } +static int tpd_probe_of(struct platform_device *pdev) +{ + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + struct omap_dss_device *in; + int gpio; + + /* CT CP HPD GPIO */ + gpio = of_get_gpio(node, 0); + if (!gpio_is_valid(gpio)) { + dev_err(&pdev->dev, "failed to parse CT CP HPD gpio\n"); + return gpio; + } + ddata->ct_cp_hpd_gpio = gpio; + + /* LS OE GPIO */ + gpio = of_get_gpio(node, 1); + if (gpio_is_valid(gpio) || gpio == -ENOENT) { + ddata->ls_oe_gpio = gpio; + } else { + dev_err(&pdev->dev, "failed to parse LS OE gpio\n"); + return gpio; + } + + /* HPD GPIO */ + gpio = of_get_gpio(node, 2); + if (!gpio_is_valid(gpio)) { + dev_err(&pdev->dev, "failed to parse HPD gpio\n"); + return gpio; + } + ddata->hpd_gpio = gpio; + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + return 0; +} + static int tpd_probe(struct platform_device *pdev) { struct omap_dss_device *in, *dssdev; @@ -307,6 +351,10 @@ static int tpd_probe(struct platform_device *pdev) r = tpd_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = tpd_probe_of(pdev); + if (r) + return r; } else { return -ENODEV; } @@ -379,12 +427,20 @@ static int __exit tpd_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id tpd_of_match[] = { + { .compatible = "omapdss,ti,tpd12s015", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, tpd_of_match); + static struct platform_driver tpd_driver = { .probe = tpd_probe, .remove = __exit_p(tpd_remove), .driver = { .name = "tpd12s015", .owner = THIS_MODULE, + .of_match_table = tpd_of_match, }, }; diff --git a/drivers/video/omap2/displays-new/panel-dsi-cm.c b/drivers/video/omap2/displays-new/panel-dsi-cm.c index b7baafe83aa3..d6f14e8717e8 100644 --- a/drivers/video/omap2/displays-new/panel-dsi-cm.c +++ b/drivers/video/omap2/displays-new/panel-dsi-cm.c @@ -22,6 +22,8 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/workqueue.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> #include <video/omapdss.h> #include <video/omap-panel-data.h> @@ -595,10 +597,13 @@ static int dsicm_power_on(struct panel_drv_data *ddata) .lp_clk_max = 10000000, }; - r = in->ops.dsi->configure_pins(in, &ddata->pin_config); - if (r) { - dev_err(&ddata->pdev->dev, "failed to configure DSI pins\n"); - goto err0; + if (ddata->pin_config.num_pins > 0) { + r = in->ops.dsi->configure_pins(in, &ddata->pin_config); + if (r) { + dev_err(&ddata->pdev->dev, + "failed to configure DSI pins\n"); + goto err0; + } } r = in->ops.dsi->set_config(in, &dsi_config); @@ -1156,6 +1161,41 @@ static int dsicm_probe_pdata(struct platform_device *pdev) return 0; } +static int dsicm_probe_of(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct omap_dss_device *in; + int gpio; + + gpio = of_get_named_gpio(node, "reset-gpios", 0); + if (!gpio_is_valid(gpio)) { + dev_err(&pdev->dev, "failed to parse reset gpio\n"); + return gpio; + } + ddata->reset_gpio = gpio; + + gpio = of_get_named_gpio(node, "te-gpios", 0); + if (gpio_is_valid(gpio) || gpio == -ENOENT) { + ddata->ext_te_gpio = gpio; + } else { + dev_err(&pdev->dev, "failed to parse TE gpio\n"); + return gpio; + } + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + /* TODO: ulps, backlight */ + + return 0; +} + static int dsicm_probe(struct platform_device *pdev) { struct backlight_properties props; @@ -1178,13 +1218,17 @@ static int dsicm_probe(struct platform_device *pdev) r = dsicm_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = dsicm_probe_of(pdev); + if (r) + return r; } else { return -ENODEV; } ddata->timings.x_res = 864; ddata->timings.y_res = 480; - ddata->timings.pixel_clock = DIV_ROUND_UP(864 * 480 * 60, 1000); + ddata->timings.pixelclock = 864 * 480 * 60; dssdev = &ddata->dssdev; dssdev->dev = dev; @@ -1320,12 +1364,20 @@ static int __exit dsicm_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id dsicm_of_match[] = { + { .compatible = "omapdss,panel-dsi-cm", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, dsicm_of_match); + static struct platform_driver dsicm_driver = { .probe = dsicm_probe, .remove = __exit_p(dsicm_remove), .driver = { .name = "panel-dsi-cm", .owner = THIS_MODULE, + .of_match_table = dsicm_of_match, }, }; diff --git a/drivers/video/omap2/displays-new/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays-new/panel-lgphilips-lb035q02.c index 6e8977b18950..2e6b513222d9 100644 --- a/drivers/video/omap2/displays-new/panel-lgphilips-lb035q02.c +++ b/drivers/video/omap2/displays-new/panel-lgphilips-lb035q02.c @@ -23,7 +23,7 @@ static struct omap_video_timings lb035q02_timings = { .x_res = 320, .y_res = 240, - .pixel_clock = 6500, + .pixelclock = 6500000, .hsw = 2, .hfp = 20, diff --git a/drivers/video/omap2/displays-new/panel-nec-nl8048hl11.c b/drivers/video/omap2/displays-new/panel-nec-nl8048hl11.c index bb217da65c5f..996fa004b48c 100644 --- a/drivers/video/omap2/displays-new/panel-nec-nl8048hl11.c +++ b/drivers/video/omap2/displays-new/panel-nec-nl8048hl11.c @@ -40,7 +40,7 @@ struct panel_drv_data { * NEC PIX Clock Ratings * MIN:21.8MHz TYP:23.8MHz MAX:25.7MHz */ -#define LCD_PIXEL_CLOCK 23800 +#define LCD_PIXEL_CLOCK 23800000 static const struct { unsigned char addr; @@ -69,7 +69,7 @@ static const struct { static const struct omap_video_timings nec_8048_panel_timings = { .x_res = LCD_XRES, .y_res = LCD_YRES, - .pixel_clock = LCD_PIXEL_CLOCK, + .pixelclock = LCD_PIXEL_CLOCK, .hfp = 6, .hsw = 1, .hbp = 4, diff --git a/drivers/video/omap2/displays-new/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays-new/panel-sharp-ls037v7dw01.c index 72a4fb5aa6b1..b2f710be565d 100644 --- a/drivers/video/omap2/displays-new/panel-sharp-ls037v7dw01.c +++ b/drivers/video/omap2/displays-new/panel-sharp-ls037v7dw01.c @@ -37,7 +37,7 @@ static const struct omap_video_timings sharp_ls_timings = { .x_res = 480, .y_res = 640, - .pixel_clock = 19200, + .pixelclock = 19200000, .hsw = 2, .hfp = 1, diff --git a/drivers/video/omap2/displays-new/panel-sony-acx565akm.c b/drivers/video/omap2/displays-new/panel-sony-acx565akm.c index 8e97d06921ff..c7ba4d8b928a 100644 --- a/drivers/video/omap2/displays-new/panel-sony-acx565akm.c +++ b/drivers/video/omap2/displays-new/panel-sony-acx565akm.c @@ -30,6 +30,8 @@ #include <linux/backlight.h> #include <linux/fb.h> #include <linux/gpio.h> +#include <linux/of.h> +#include <linux/of_gpio.h> #include <video/omapdss.h> #include <video/omap-panel-data.h> @@ -93,7 +95,7 @@ struct panel_drv_data { static const struct omap_video_timings acx565akm_panel_timings = { .x_res = 800, .y_res = 480, - .pixel_clock = 24000, + .pixelclock = 24000000, .hfp = 28, .hsw = 4, .hbp = 24, @@ -547,7 +549,9 @@ static int acx565akm_panel_power_on(struct omap_dss_device *dssdev) dev_dbg(&ddata->spi->dev, "%s\n", __func__); in->ops.sdi->set_timings(in, &ddata->videomode); - in->ops.sdi->set_datapairs(in, ddata->datapairs); + + if (ddata->datapairs > 0) + in->ops.sdi->set_datapairs(in, ddata->datapairs); r = in->ops.sdi->enable(in); if (r) { @@ -726,6 +730,22 @@ static int acx565akm_probe_pdata(struct spi_device *spi) return 0; } +static int acx565akm_probe_of(struct spi_device *spi) +{ + struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); + struct device_node *np = spi->dev.of_node; + + ddata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); + + ddata->in = omapdss_of_find_source_for_first_ep(np); + if (IS_ERR(ddata->in)) { + dev_err(&spi->dev, "failed to find video source\n"); + return PTR_ERR(ddata->in); + } + + return 0; +} + static int acx565akm_probe(struct spi_device *spi) { struct panel_drv_data *ddata; @@ -753,7 +773,12 @@ static int acx565akm_probe(struct spi_device *spi) r = acx565akm_probe_pdata(spi); if (r) return r; + } else if (spi->dev.of_node) { + r = acx565akm_probe_of(spi); + if (r) + return r; } else { + dev_err(&spi->dev, "platform data missing!\n"); return -ENODEV; } @@ -864,10 +889,16 @@ static int acx565akm_remove(struct spi_device *spi) return 0; } +static const struct of_device_id acx565akm_of_match[] = { + { .compatible = "omapdss,sony,acx565akm", }, + {}, +}; + static struct spi_driver acx565akm_driver = { .driver = { .name = "acx565akm", .owner = THIS_MODULE, + .of_match_table = acx565akm_of_match, }, .probe = acx565akm_probe, .remove = acx565akm_remove, diff --git a/drivers/video/omap2/displays-new/panel-tpo-td028ttec1.c b/drivers/video/omap2/displays-new/panel-tpo-td028ttec1.c index 9a08908fe998..fae6adc005a7 100644 --- a/drivers/video/omap2/displays-new/panel-tpo-td028ttec1.c +++ b/drivers/video/omap2/displays-new/panel-tpo-td028ttec1.c @@ -45,7 +45,7 @@ struct panel_drv_data { static struct omap_video_timings td028ttec1_panel_timings = { .x_res = 480, .y_res = 640, - .pixel_clock = 22153, + .pixelclock = 22153000, .hfp = 24, .hsw = 8, .hbp = 8, diff --git a/drivers/video/omap2/displays-new/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays-new/panel-tpo-td043mtea1.c index eadc6529fa3d..875b40263b33 100644 --- a/drivers/video/omap2/displays-new/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays-new/panel-tpo-td043mtea1.c @@ -76,7 +76,7 @@ static const struct omap_video_timings tpo_td043_timings = { .x_res = 800, .y_res = 480, - .pixel_clock = 36000, + .pixelclock = 36000000, .hsw = 1, .hfp = 68, diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index d3aa91bdd6a8..8aec8bda27cc 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile @@ -1,7 +1,7 @@ obj-$(CONFIG_OMAP2_DSS) += omapdss.o # Core DSS files omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ - output.o + output.o dss-of.o # DSS compat layer files omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \ dispc-compat.o display-sysfs.o diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index bbeb8dd7f108..2bbdb7ff7daf 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -100,8 +100,6 @@ static struct { struct platform_device *pdev; void __iomem *base; - int ctx_loss_cnt; - int irq; unsigned long core_clk_rate; @@ -357,29 +355,20 @@ static void dispc_save_context(void) if (dss_has_feature(FEAT_CORE_CLK_DIV)) SR(DIVISOR); - dispc.ctx_loss_cnt = dss_get_ctx_loss_count(); dispc.ctx_valid = true; - DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt); + DSSDBG("context saved\n"); } static void dispc_restore_context(void) { - int i, j, ctx; + int i, j; DSSDBG("dispc_restore_context\n"); if (!dispc.ctx_valid) return; - ctx = dss_get_ctx_loss_count(); - - if (ctx >= 0 && ctx == dispc.ctx_loss_cnt) - return; - - DSSDBG("ctx_loss_count: saved %d, current %d\n", - dispc.ctx_loss_cnt, ctx); - /*RR(IRQENABLE);*/ /*RR(CONTROL);*/ RR(CONFIG); @@ -2160,8 +2149,8 @@ static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk, *five_taps = false; do { - in_height = DIV_ROUND_UP(height, *decim_y); - in_width = DIV_ROUND_UP(width, *decim_x); + in_height = height / *decim_y; + in_width = width / *decim_x; *core_clk = dispc.feat->calc_core_clk(pclk, in_width, in_height, out_width, out_height, mem_to_mem); error = (in_width > maxsinglelinewidth || !*core_clk || @@ -2199,8 +2188,8 @@ static int dispc_ovl_calc_scaling_34xx(unsigned long pclk, unsigned long lclk, dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); do { - in_height = DIV_ROUND_UP(height, *decim_y); - in_width = DIV_ROUND_UP(width, *decim_x); + in_height = height / *decim_y; + in_width = width / *decim_x; *five_taps = in_height > out_height; if (in_width > maxsinglelinewidth) @@ -2268,7 +2257,7 @@ static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk, { u16 in_width, in_width_max; int decim_x_min = *decim_x; - u16 in_height = DIV_ROUND_UP(height, *decim_y); + u16 in_height = height / *decim_y; const int maxsinglelinewidth = dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); @@ -2287,7 +2276,7 @@ static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk, return -EINVAL; do { - in_width = DIV_ROUND_UP(width, *decim_x); + in_width = width / *decim_x; } while (*decim_x <= *x_predecim && in_width > maxsinglelinewidth && ++*decim_x); @@ -2466,8 +2455,8 @@ static int dispc_ovl_setup_common(enum omap_plane plane, if (r) return r; - in_width = DIV_ROUND_UP(in_width, x_predecim); - in_height = DIV_ROUND_UP(in_height, y_predecim); + in_width = in_width / x_predecim; + in_height = in_height / y_predecim; if (color_mode == OMAP_DSS_COLOR_YUV2 || color_mode == OMAP_DSS_COLOR_UYVY || @@ -2884,7 +2873,7 @@ bool dispc_mgr_timings_ok(enum omap_channel channel, timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res); - timings_ok &= _dispc_mgr_pclk_ok(channel, timings->pixel_clock * 1000); + timings_ok &= _dispc_mgr_pclk_ok(channel, timings->pixelclock); if (dss_mgr_is_lcd(channel)) { timings_ok &= _dispc_lcd_timings_ok(timings->hsw, timings->hfp, @@ -2979,10 +2968,10 @@ void dispc_mgr_set_timings(enum omap_channel channel, xtot = t.x_res + t.hfp + t.hsw + t.hbp; ytot = t.y_res + t.vfp + t.vsw + t.vbp; - ht = (timings->pixel_clock * 1000) / xtot; - vt = (timings->pixel_clock * 1000) / xtot / ytot; + ht = timings->pixelclock / xtot; + vt = timings->pixelclock / xtot / ytot; - DSSDBG("pck %u\n", timings->pixel_clock); + DSSDBG("pck %u\n", timings->pixelclock); DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n", t.hsw, t.hfp, t.hbp, t.vsw, t.vfp, t.vbp); DSSDBG("vsync_level %d hsync_level %d data_pclk_edge %d de_level %d sync_pclk_edge %d\n", @@ -3768,6 +3757,15 @@ static int dispc_runtime_suspend(struct device *dev) static int dispc_runtime_resume(struct device *dev) { + /* + * The reset value for load mode is 0 (OMAP_DSS_LOAD_CLUT_AND_FRAME) + * but we always initialize it to 2 (OMAP_DSS_LOAD_FRAME_ONLY) in + * _omap_dispc_initial_config(). We can thus use it to detect if + * we have lost register context. + */ + if (REG_GET(DISPC_CONFIG, 2, 1) == OMAP_DSS_LOAD_FRAME_ONLY) + return 0; + _omap_dispc_initial_config(); dispc_restore_context(); @@ -3780,12 +3778,20 @@ static const struct dev_pm_ops dispc_pm_ops = { .runtime_resume = dispc_runtime_resume, }; +static const struct of_device_id dispc_of_match[] = { + { .compatible = "ti,omap2-dispc", }, + { .compatible = "ti,omap3-dispc", }, + { .compatible = "ti,omap4-dispc", }, + {}, +}; + static struct platform_driver omap_dispchw_driver = { .remove = __exit_p(omap_dispchw_remove), .driver = { .name = "omapdss_dispc", .owner = THIS_MODULE, .pm = &dispc_pm_ops, + .of_match_table = dispc_of_match, }, }; diff --git a/drivers/video/omap2/dss/display-sysfs.c b/drivers/video/omap2/dss/display-sysfs.c index f7b5f9561041..5a2095a98ed8 100644 --- a/drivers/video/omap2/dss/display-sysfs.c +++ b/drivers/video/omap2/dss/display-sysfs.c @@ -132,7 +132,7 @@ static ssize_t display_timings_show(struct device *dev, dssdev->driver->get_timings(dssdev, &t); return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n", - t.pixel_clock, + t.pixelclock, t.x_res, t.hfp, t.hbp, t.hsw, t.y_res, t.vfp, t.vbp, t.vsw); } @@ -158,7 +158,7 @@ static ssize_t display_timings_store(struct device *dev, } #endif if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu", - &t.pixel_clock, + &t.pixelclock, &t.x_res, &t.hfp, &t.hbp, &t.hsw, &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9) return -EINVAL; diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 669a81fdf58e..2412a0dd0c13 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/jiffies.h> #include <linux/platform_device.h> +#include <linux/of.h> #include <video/omapdss.h> #include "dss.h" @@ -133,9 +134,32 @@ static int disp_num_counter; int omapdss_register_display(struct omap_dss_device *dssdev) { struct omap_dss_driver *drv = dssdev->driver; + int id; - snprintf(dssdev->alias, sizeof(dssdev->alias), - "display%d", disp_num_counter++); + /* + * Note: this presumes all the displays are either using DT or non-DT, + * which normally should be the case. This also presumes that all + * displays either have an DT alias, or none has. + */ + + if (dssdev->dev->of_node) { + id = of_alias_get_id(dssdev->dev->of_node, "display"); + + if (id < 0) + id = disp_num_counter++; + } else { + id = disp_num_counter++; + } + + snprintf(dssdev->alias, sizeof(dssdev->alias), "display%d", id); + + /* Use 'label' property for name, if it exists */ + if (dssdev->dev->of_node) + of_property_read_string(dssdev->dev->of_node, "label", + &dssdev->name); + + if (dssdev->name == NULL) + dssdev->name = dssdev->alias; if (drv && drv->get_resolution == NULL) drv->get_resolution = omapdss_default_get_resolution; @@ -248,7 +272,7 @@ void videomode_to_omap_video_timings(const struct videomode *vm, { memset(ovt, 0, sizeof(*ovt)); - ovt->pixel_clock = vm->pixelclock / 1000; + ovt->pixelclock = vm->pixelclock; ovt->x_res = vm->hactive; ovt->hbp = vm->hback_porch; ovt->hfp = vm->hfront_porch; @@ -280,7 +304,7 @@ void omap_video_timings_to_videomode(const struct omap_video_timings *ovt, { memset(vm, 0, sizeof(*vm)); - vm->pixelclock = ovt->pixel_clock * 1000; + vm->pixelclock = ovt->pixelclock; vm->hactive = ovt->x_res; vm->hback_porch = ovt->hbp; diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 7411f2674e16..157921db447a 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -30,6 +30,7 @@ #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/string.h> +#include <linux/of.h> #include <video/omapdss.h> @@ -49,6 +50,8 @@ static struct { int data_lines; struct omap_dss_device output; + + bool port_initialized; } dpi; static struct platform_device *dpi_get_dsidev(enum omap_channel channel) @@ -117,7 +120,7 @@ struct dpi_clk_calc_ctx { /* outputs */ struct dsi_clock_info dsi_cinfo; - unsigned long long fck; + unsigned long fck; struct dispc_clock_info dispc_cinfo; }; @@ -307,22 +310,21 @@ static int dpi_set_mode(struct omap_overlay_manager *mgr) int r = 0; if (dpi.dsidev) - r = dpi_set_dsi_clk(mgr->id, t->pixel_clock * 1000, &fck, + r = dpi_set_dsi_clk(mgr->id, t->pixelclock, &fck, &lck_div, &pck_div); else - r = dpi_set_dispc_clk(t->pixel_clock * 1000, &fck, + r = dpi_set_dispc_clk(t->pixelclock, &fck, &lck_div, &pck_div); if (r) return r; - pck = fck / lck_div / pck_div / 1000; + pck = fck / lck_div / pck_div; - if (pck != t->pixel_clock) { - DSSWARN("Could not find exact pixel clock. " - "Requested %d kHz, got %lu kHz\n", - t->pixel_clock, pck); + if (pck != t->pixelclock) { + DSSWARN("Could not find exact pixel clock. Requested %d Hz, got %lu Hz\n", + t->pixelclock, pck); - t->pixel_clock = pck; + t->pixelclock = pck; } dss_mgr_set_timings(mgr, t); @@ -480,17 +482,17 @@ static int dpi_check_timings(struct omap_dss_device *dssdev, if (mgr && !dispc_mgr_timings_ok(mgr->id, timings)) return -EINVAL; - if (timings->pixel_clock == 0) + if (timings->pixelclock == 0) return -EINVAL; if (dpi.dsidev) { - ok = dpi_dsi_clk_calc(timings->pixel_clock * 1000, &ctx); + ok = dpi_dsi_clk_calc(timings->pixelclock, &ctx); if (!ok) return -EINVAL; fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk; } else { - ok = dpi_dss_clk_calc(timings->pixel_clock * 1000, &ctx); + ok = dpi_dss_clk_calc(timings->pixelclock, &ctx); if (!ok) return -EINVAL; @@ -500,9 +502,9 @@ static int dpi_check_timings(struct omap_dss_device *dssdev, lck_div = ctx.dispc_cinfo.lck_div; pck_div = ctx.dispc_cinfo.pck_div; - pck = fck / lck_div / pck_div / 1000; + pck = fck / lck_div / pck_div; - timings->pixel_clock = pck; + timings->pixelclock = pck; return 0; } @@ -726,3 +728,47 @@ void __exit dpi_uninit_platform_driver(void) { platform_driver_unregister(&omap_dpi_driver); } + +int __init dpi_init_port(struct platform_device *pdev, struct device_node *port) +{ + struct device_node *ep; + u32 datalines; + int r; + + ep = omapdss_of_get_next_endpoint(port, NULL); + if (!ep) + return 0; + + r = of_property_read_u32(ep, "data-lines", &datalines); + if (r) { + DSSERR("failed to parse datalines\n"); + goto err_datalines; + } + + dpi.data_lines = datalines; + + of_node_put(ep); + + dpi.pdev = pdev; + + mutex_init(&dpi.lock); + + dpi_init_output(pdev); + + dpi.port_initialized = true; + + return 0; + +err_datalines: + of_node_put(ep); + + return r; +} + +void __exit dpi_uninit_port(void) +{ + if (!dpi.port_initialized) + return; + + dpi_uninit_output(dpi.pdev); +} diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index a820c37e323e..121d1049d0bc 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -38,6 +38,8 @@ #include <linux/slab.h> #include <linux/debugfs.h> #include <linux/pm_runtime.h> +#include <linux/of.h> +#include <linux/of_platform.h> #include <video/omapdss.h> #include <video/mipi_display.h> @@ -386,6 +388,13 @@ struct dsi_packet_sent_handler_data { struct completion *completion; }; +struct dsi_module_id_data { + u32 address; + int id; +}; + +static const struct of_device_id dsi_of_match[]; + #ifdef DSI_PERF_MEASURE static bool dsi_perf; module_param(dsi_perf, bool, 0644); @@ -1151,15 +1160,11 @@ static int dsi_regulator_init(struct platform_device *dsidev) if (dsi->vdds_dsi_reg != NULL) return 0; - vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdds_dsi"); - - /* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */ - if (IS_ERR(vdds_dsi)) - vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "VCXIO"); + vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdd"); if (IS_ERR(vdds_dsi)) { if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER) - DSSERR("can't get VDDS_DSI regulator\n"); + DSSERR("can't get DSI VDD regulator\n"); return PTR_ERR(vdds_dsi); } @@ -4616,7 +4621,7 @@ static void print_dsi_vm(const char *str, static void print_dispc_vm(const char *str, const struct omap_video_timings *t) { - unsigned long pck = t->pixel_clock * 1000; + unsigned long pck = t->pixelclock; int hact, bl, tot; hact = t->x_res; @@ -4656,7 +4661,7 @@ static void print_dsi_dispc_vm(const char *str, dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(t->hact * t->bitspp, 8) + 6, t->ndl); dsi_htot = t->hss + t->hsa + t->hse + t->hbp + dsi_hact + t->hfp; - vm.pixel_clock = pck / 1000; + vm.pixelclock = pck; vm.hsw = div64_u64((u64)(t->hsa + t->hse) * pck, byteclk); vm.hbp = div64_u64((u64)t->hbp * pck, byteclk); vm.hfp = div64_u64((u64)t->hfp * pck, byteclk); @@ -4678,7 +4683,7 @@ static bool dsi_cm_calc_dispc_cb(int lckd, int pckd, unsigned long lck, ctx->dispc_cinfo.pck = pck; *t = *ctx->config->timings; - t->pixel_clock = pck / 1000; + t->pixelclock = pck; t->x_res = ctx->config->timings->x_res; t->y_res = ctx->config->timings->y_res; t->hsw = t->hfp = t->hbp = t->vsw = 1; @@ -4732,7 +4737,7 @@ static bool dsi_cm_calc(struct dsi_data *dsi, * especially as we go to LP between each pixel packet due to HW * "feature". So let's just estimate very roughly and multiply by 1.5. */ - pck = cfg->timings->pixel_clock * 1000; + pck = cfg->timings->pixelclock; pck = pck * 3 / 2; txbyteclk = pck * bitspp / 8 / ndl; @@ -4909,7 +4914,7 @@ static bool dsi_vm_calc_blanking(struct dsi_clk_calc_ctx *ctx) dispc_vm = &ctx->dispc_vm; *dispc_vm = *req_vm; - dispc_vm->pixel_clock = dispc_pck / 1000; + dispc_vm->pixelclock = dispc_pck; if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) { hsa = div64_u64((u64)req_vm->hsw * dispc_pck, @@ -5031,9 +5036,9 @@ static bool dsi_vm_calc(struct dsi_data *dsi, ctx->dsi_cinfo.clkin = clkin; /* these limits should come from the panel driver */ - ctx->req_pck_min = t->pixel_clock * 1000 - 1000; - ctx->req_pck_nom = t->pixel_clock * 1000; - ctx->req_pck_max = t->pixel_clock * 1000 + 1000; + ctx->req_pck_min = t->pixelclock - 1000; + ctx->req_pck_nom = t->pixelclock; + ctx->req_pck_max = t->pixelclock + 1000; byteclk_min = div64_u64((u64)ctx->req_pck_min * bitspp, ndl * 8); pll_min = max(cfg->hs_clk_min * 4, byteclk_min * 4 * 4); @@ -5370,12 +5375,69 @@ static void dsi_uninit_output(struct platform_device *dsidev) omapdss_unregister_output(out); } +static int dsi_probe_of(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); + struct property *prop; + u32 lane_arr[10]; + int len, num_pins; + int r, i; + struct device_node *ep; + struct omap_dsi_pin_config pin_cfg; + + ep = omapdss_of_get_first_endpoint(node); + if (!ep) + return 0; + + prop = of_find_property(ep, "lanes", &len); + if (prop == NULL) { + dev_err(&pdev->dev, "failed to find lane data\n"); + r = -EINVAL; + goto err; + } + + num_pins = len / sizeof(u32); + + if (num_pins < 4 || num_pins % 2 != 0 || + num_pins > dsi->num_lanes_supported * 2) { + dev_err(&pdev->dev, "bad number of lanes\n"); + r = -EINVAL; + goto err; + } + + r = of_property_read_u32_array(ep, "lanes", lane_arr, num_pins); + if (r) { + dev_err(&pdev->dev, "failed to read lane data\n"); + goto err; + } + + pin_cfg.num_pins = num_pins; + for (i = 0; i < num_pins; ++i) + pin_cfg.pins[i] = (int)lane_arr[i]; + + r = dsi_configure_pins(&dsi->output, &pin_cfg); + if (r) { + dev_err(&pdev->dev, "failed to configure pins"); + goto err; + } + + of_node_put(ep); + + return 0; + +err: + of_node_put(ep); + return r; +} + /* DSI1 HW IP initialisation */ static int omap_dsihw_probe(struct platform_device *dsidev) { u32 rev; int r, i; struct dsi_data *dsi; + struct resource *dsi_mem; struct resource *res; struct resource temp_res; @@ -5383,7 +5445,6 @@ static int omap_dsihw_probe(struct platform_device *dsidev) if (!dsi) return -ENOMEM; - dsi->module_id = dsidev->id; dsi->pdev = dsidev; dev_set_drvdata(&dsidev->dev, dsi); @@ -5421,6 +5482,8 @@ static int omap_dsihw_probe(struct platform_device *dsidev) res = &temp_res; } + dsi_mem = res; + dsi->proto_base = devm_ioremap(&dsidev->dev, res->start, resource_size(res)); if (!dsi->proto_base) { @@ -5481,6 +5544,31 @@ static int omap_dsihw_probe(struct platform_device *dsidev) return r; } + if (dsidev->dev.of_node) { + const struct of_device_id *match; + const struct dsi_module_id_data *d; + + match = of_match_node(dsi_of_match, dsidev->dev.of_node); + if (!match) { + DSSERR("unsupported DSI module\n"); + return -ENODEV; + } + + d = match->data; + + while (d->address != 0 && d->address != dsi_mem->start) + d++; + + if (d->address == 0) { + DSSERR("unsupported DSI module\n"); + return -ENODEV; + } + + dsi->module_id = d->id; + } else { + dsi->module_id = dsidev->id; + } + /* DSI VCs initialization */ for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) { dsi->vc[i].source = DSI_VC_SOURCE_L4; @@ -5516,6 +5604,19 @@ static int omap_dsihw_probe(struct platform_device *dsidev) dsi_init_output(dsidev); + if (dsidev->dev.of_node) { + r = dsi_probe_of(dsidev); + if (r) { + DSSERR("Invalid DSI DT data\n"); + goto err_probe_of; + } + + r = of_platform_populate(dsidev->dev.of_node, NULL, NULL, + &dsidev->dev); + if (r) + DSSERR("Failed to populate DSI child devices: %d\n", r); + } + dsi_runtime_put(dsidev); if (dsi->module_id == 0) @@ -5529,17 +5630,31 @@ static int omap_dsihw_probe(struct platform_device *dsidev) else if (dsi->module_id == 1) dss_debugfs_create_file("dsi2_irqs", dsi2_dump_irqs); #endif + return 0; +err_probe_of: + dsi_uninit_output(dsidev); + dsi_runtime_put(dsidev); + err_runtime_get: pm_runtime_disable(&dsidev->dev); return r; } +static int dsi_unregister_child(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + platform_device_unregister(pdev); + return 0; +} + static int __exit omap_dsihw_remove(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + device_for_each_child(&dsidev->dev, NULL, dsi_unregister_child); + WARN_ON(dsi->scp_clk_refcount > 0); dsi_uninit_output(dsidev); @@ -5577,6 +5692,23 @@ static const struct dev_pm_ops dsi_pm_ops = { .runtime_resume = dsi_runtime_resume, }; +static const struct dsi_module_id_data dsi_of_data_omap3[] = { + { .address = 0x4804fc00, .id = 0, }, + { }, +}; + +static const struct dsi_module_id_data dsi_of_data_omap4[] = { + { .address = 0x58004000, .id = 0, }, + { .address = 0x58005000, .id = 1, }, + { }, +}; + +static const struct of_device_id dsi_of_match[] = { + { .compatible = "ti,omap3-dsi", .data = dsi_of_data_omap3, }, + { .compatible = "ti,omap4-dsi", .data = dsi_of_data_omap4, }, + {}, +}; + static struct platform_driver omap_dsihw_driver = { .probe = omap_dsihw_probe, .remove = __exit_p(omap_dsihw_remove), @@ -5584,6 +5716,7 @@ static struct platform_driver omap_dsihw_driver = { .name = "omapdss_dsi", .owner = THIS_MODULE, .pm = &dsi_pm_ops, + .of_match_table = dsi_of_match, }, }; diff --git a/drivers/video/omap2/dss/dss-of.c b/drivers/video/omap2/dss/dss-of.c new file mode 100644 index 000000000000..a4b20aaf6142 --- /dev/null +++ b/drivers/video/omap2/dss/dss-of.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2013 Texas Instruments + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/seq_file.h> + +#include <video/omapdss.h> + +struct device_node * +omapdss_of_get_next_port(const struct device_node *parent, + struct device_node *prev) +{ + struct device_node *port = NULL; + + if (!parent) + return NULL; + + if (!prev) { + struct device_node *ports; + /* + * It's the first call, we have to find a port subnode + * within this node or within an optional 'ports' node. + */ + ports = of_get_child_by_name(parent, "ports"); + if (ports) + parent = ports; + + port = of_get_child_by_name(parent, "port"); + + /* release the 'ports' node */ + of_node_put(ports); + } else { + struct device_node *ports; + + ports = of_get_parent(prev); + if (!ports) + return NULL; + + do { + port = of_get_next_child(ports, prev); + if (!port) { + of_node_put(ports); + return NULL; + } + prev = port; + } while (of_node_cmp(port->name, "port") != 0); + } + + return port; +} +EXPORT_SYMBOL_GPL(omapdss_of_get_next_port); + +struct device_node * +omapdss_of_get_next_endpoint(const struct device_node *parent, + struct device_node *prev) +{ + struct device_node *ep = NULL; + + if (!parent) + return NULL; + + do { + ep = of_get_next_child(parent, prev); + if (!ep) + return NULL; + prev = ep; + } while (of_node_cmp(ep->name, "endpoint") != 0); + + return ep; +} +EXPORT_SYMBOL_GPL(omapdss_of_get_next_endpoint); + +static struct device_node * +omapdss_of_get_remote_device_node(const struct device_node *node) +{ + struct device_node *np; + int i; + + np = of_parse_phandle(node, "remote-endpoint", 0); + + if (!np) + return NULL; + + np = of_get_next_parent(np); + + for (i = 0; i < 3 && np; ++i) { + struct property *prop; + + prop = of_find_property(np, "compatible", NULL); + + if (prop) + return np; + + np = of_get_next_parent(np); + } + + return NULL; +} + +struct device_node * +omapdss_of_get_first_endpoint(const struct device_node *parent) +{ + struct device_node *port, *ep; + + port = omapdss_of_get_next_port(parent, NULL); + + if (!port) + return NULL; + + ep = omapdss_of_get_next_endpoint(port, NULL); + + of_node_put(port); + + return ep; +} +EXPORT_SYMBOL_GPL(omapdss_of_get_first_endpoint); + +struct omap_dss_device * +omapdss_of_find_source_for_first_ep(struct device_node *node) +{ + struct device_node *ep; + struct device_node *src_node; + struct omap_dss_device *src; + + ep = omapdss_of_get_first_endpoint(node); + if (!ep) + return ERR_PTR(-EINVAL); + + src_node = omapdss_of_get_remote_device_node(ep); + + of_node_put(ep); + + if (!src_node) + return ERR_PTR(-EINVAL); + + src = omap_dss_find_output_by_node(src_node); + + of_node_put(src_node); + + if (!src) + return ERR_PTR(-EPROBE_DEFER); + + return src; +} +EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep); diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 9a145da35ad3..825c019ddee7 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -23,6 +23,7 @@ #define DSS_SUBSYS_NAME "DSS" #include <linux/kernel.h> +#include <linux/module.h> #include <linux/io.h> #include <linux/export.h> #include <linux/err.h> @@ -33,6 +34,7 @@ #include <linux/pm_runtime.h> #include <linux/gfp.h> #include <linux/sizes.h> +#include <linux/of.h> #include <video/omapdss.h> @@ -154,22 +156,6 @@ static void dss_restore_context(void) #undef SR #undef RR -int dss_get_ctx_loss_count(void) -{ - struct platform_device *core_pdev = dss_get_core_pdev(); - struct omap_dss_board_info *board_data = core_pdev->dev.platform_data; - int cnt; - - if (!board_data->get_context_loss_count) - return -ENOENT; - - cnt = board_data->get_context_loss_count(&dss.pdev->dev); - - WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt); - - return cnt; -} - void dss_sdi_init(int datapairs) { u32 l; @@ -788,6 +774,56 @@ static int __init dss_init_features(struct platform_device *pdev) return 0; } +static int __init dss_init_ports(struct platform_device *pdev) +{ + struct device_node *parent = pdev->dev.of_node; + struct device_node *port; + int r; + + if (parent == NULL) + return 0; + + port = omapdss_of_get_next_port(parent, NULL); + if (!port) { +#ifdef CONFIG_OMAP2_DSS_DPI + dpi_init_port(pdev, parent); +#endif + return 0; + } + + do { + u32 reg; + + r = of_property_read_u32(port, "reg", ®); + if (r) + reg = 0; + +#ifdef CONFIG_OMAP2_DSS_DPI + if (reg == 0) + dpi_init_port(pdev, port); +#endif + +#ifdef CONFIG_OMAP2_DSS_SDI + if (reg == 1) + sdi_init_port(pdev, port); +#endif + + } while ((port = omapdss_of_get_next_port(parent, port)) != NULL); + + return 0; +} + +static void dss_uninit_ports(void) +{ +#ifdef CONFIG_OMAP2_DSS_DPI + dpi_uninit_port(); +#endif + +#ifdef CONFIG_OMAP2_DSS_SDI + sdi_uninit_port(); +#endif +} + /* DSS HW IP initialisation */ static int __init omap_dsshw_probe(struct platform_device *pdev) { @@ -846,6 +882,8 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; + dss_init_ports(pdev); + rev = dss_read_reg(DSS_REVISION); printk(KERN_INFO "OMAP DSS rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); @@ -865,6 +903,8 @@ err_setup_clocks: static int __exit omap_dsshw_remove(struct platform_device *pdev) { + dss_uninit_ports(); + pm_runtime_disable(&pdev->dev); dss_put_clocks(); @@ -902,12 +942,22 @@ static const struct dev_pm_ops dss_pm_ops = { .runtime_resume = dss_runtime_resume, }; +static const struct of_device_id dss_of_match[] = { + { .compatible = "ti,omap2-dss", }, + { .compatible = "ti,omap3-dss", }, + { .compatible = "ti,omap4-dss", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, dss_of_match); + static struct platform_driver omap_dsshw_driver = { .remove = __exit_p(omap_dsshw_remove), .driver = { .name = "omapdss_dss", .owner = THIS_MODULE, .pm = &dss_pm_ops, + .of_match_table = dss_of_match, }, }; diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 057f24c8a332..918fec182424 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -225,8 +225,6 @@ void dss_dump_clocks(struct seq_file *s); void dss_debug_dump_clocks(struct seq_file *s); #endif -int dss_get_ctx_loss_count(void); - void dss_sdi_init(int datapairs); int dss_sdi_enable(void); void dss_sdi_disable(void); @@ -252,6 +250,9 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min, int sdi_init_platform_driver(void) __init; void sdi_uninit_platform_driver(void) __exit; +int sdi_init_port(struct platform_device *pdev, struct device_node *port) __init; +void sdi_uninit_port(void) __exit; + /* DSI */ typedef bool (*dsi_pll_calc_func)(int regn, int regm, unsigned long fint, @@ -363,6 +364,9 @@ static inline bool dsi_pll_calc(struct platform_device *dsidev, int dpi_init_platform_driver(void) __init; void dpi_uninit_platform_driver(void) __exit; +int dpi_init_port(struct platform_device *pdev, struct device_node *port) __init; +void dpi_uninit_port(void) __exit; + /* DISPC */ int dispc_init_platform_driver(void) __init; void dispc_uninit_platform_driver(void) __exit; diff --git a/drivers/video/omap2/dss/hdmi4.c b/drivers/video/omap2/dss/hdmi4.c index 4a74538f9ea5..f5f7944a1fd1 100644 --- a/drivers/video/omap2/dss/hdmi4.c +++ b/drivers/video/omap2/dss/hdmi4.c @@ -88,15 +88,11 @@ static int hdmi_init_regulator(void) if (hdmi.vdda_hdmi_dac_reg != NULL) return 0; - reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac"); - - /* DT HACK: try VDAC to make omapdss work for o4 sdp/panda */ - if (IS_ERR(reg)) - reg = devm_regulator_get(&hdmi.pdev->dev, "VDAC"); + reg = devm_regulator_get(&hdmi.pdev->dev, "vdda"); if (IS_ERR(reg)) { if (PTR_ERR(reg) != -EPROBE_DEFER) - DSSERR("can't get VDDA_HDMI_DAC regulator\n"); + DSSERR("can't get VDDA regulator\n"); return PTR_ERR(reg); } @@ -153,7 +149,8 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); - phy = p->pixel_clock; + /* the functions below use kHz pixel clock. TODO: change to Hz */ + phy = p->pixelclock / 1000; hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy); @@ -238,13 +235,13 @@ static void hdmi_display_set_timing(struct omap_dss_device *dssdev, if (t != NULL) { hdmi.cfg = *t; - dispc_set_tv_pclk(t->timings.pixel_clock * 1000); + dispc_set_tv_pclk(t->timings.pixelclock); } else { hdmi.cfg.timings = *timings; hdmi.cfg.cm.code = 0; hdmi.cfg.cm.mode = HDMI_DVI; - dispc_set_tv_pclk(timings->pixel_clock * 1000); + dispc_set_tv_pclk(timings->pixelclock); } DSSDBG("using mode: %s, code %d\n", hdmi.cfg.cm.mode == HDMI_DVI ? @@ -509,7 +506,7 @@ static int hdmi_audio_config(struct omap_dss_device *dssdev, struct omap_dss_audio *audio) { int r; - u32 pclk = hdmi.cfg.timings.pixel_clock; + u32 pclk = hdmi.cfg.timings.pixelclock; mutex_lock(&hdmi.lock); @@ -679,6 +676,11 @@ static const struct dev_pm_ops hdmi_pm_ops = { .runtime_resume = hdmi_runtime_resume, }; +static const struct of_device_id hdmi_of_match[] = { + { .compatible = "ti,omap4-hdmi", }, + {}, +}; + static struct platform_driver omapdss_hdmihw_driver = { .probe = omapdss_hdmihw_probe, .remove = __exit_p(omapdss_hdmihw_remove), @@ -686,6 +688,7 @@ static struct platform_driver omapdss_hdmihw_driver = { .name = "omapdss_hdmi", .owner = THIS_MODULE, .pm = &hdmi_pm_ops, + .of_match_table = hdmi_of_match, }, }; diff --git a/drivers/video/omap2/dss/hdmi_common.c b/drivers/video/omap2/dss/hdmi_common.c index 0614922902dd..b11afac8e068 100644 --- a/drivers/video/omap2/dss/hdmi_common.c +++ b/drivers/video/omap2/dss/hdmi_common.c @@ -23,91 +23,91 @@ static const struct hdmi_config cea_timings[] = { { - { 640, 480, 25200, 96, 16, 48, 2, 10, 33, + { 640, 480, 25200000, 96, 16, 48, 2, 10, 33, OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, false, }, { 1, HDMI_HDMI }, }, { - { 720, 480, 27027, 62, 16, 60, 6, 9, 30, + { 720, 480, 27027000, 62, 16, 60, 6, 9, 30, OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, false, }, { 2, HDMI_HDMI }, }, { - { 1280, 720, 74250, 40, 110, 220, 5, 5, 20, + { 1280, 720, 74250000, 40, 110, 220, 5, 5, 20, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, false, }, { 4, HDMI_HDMI }, }, { - { 1920, 540, 74250, 44, 88, 148, 5, 2, 15, + { 1920, 540, 74250000, 44, 88, 148, 5, 2, 15, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, true, }, { 5, HDMI_HDMI }, }, { - { 1440, 240, 27027, 124, 38, 114, 3, 4, 15, + { 1440, 240, 27027000, 124, 38, 114, 3, 4, 15, OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, true, }, { 6, HDMI_HDMI }, }, { - { 1920, 1080, 148500, 44, 88, 148, 5, 4, 36, + { 1920, 1080, 148500000, 44, 88, 148, 5, 4, 36, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, false, }, { 16, HDMI_HDMI }, }, { - { 720, 576, 27000, 64, 12, 68, 5, 5, 39, + { 720, 576, 27000000, 64, 12, 68, 5, 5, 39, OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, false, }, { 17, HDMI_HDMI }, }, { - { 1280, 720, 74250, 40, 440, 220, 5, 5, 20, + { 1280, 720, 74250000, 40, 440, 220, 5, 5, 20, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, false, }, { 19, HDMI_HDMI }, }, { - { 1920, 540, 74250, 44, 528, 148, 5, 2, 15, + { 1920, 540, 74250000, 44, 528, 148, 5, 2, 15, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, true, }, { 20, HDMI_HDMI }, }, { - { 1440, 288, 27000, 126, 24, 138, 3, 2, 19, + { 1440, 288, 27000000, 126, 24, 138, 3, 2, 19, OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, true, }, { 21, HDMI_HDMI }, }, { - { 1440, 576, 54000, 128, 24, 136, 5, 5, 39, + { 1440, 576, 54000000, 128, 24, 136, 5, 5, 39, OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, false, }, { 29, HDMI_HDMI }, }, { - { 1920, 1080, 148500, 44, 528, 148, 5, 4, 36, + { 1920, 1080, 148500000, 44, 528, 148, 5, 4, 36, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, false, }, { 31, HDMI_HDMI }, }, { - { 1920, 1080, 74250, 44, 638, 148, 5, 4, 36, + { 1920, 1080, 74250000, 44, 638, 148, 5, 4, 36, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, false, }, { 32, HDMI_HDMI }, }, { - { 2880, 480, 108108, 248, 64, 240, 6, 9, 30, + { 2880, 480, 108108000, 248, 64, 240, 6, 9, 30, OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, false, }, { 35, HDMI_HDMI }, }, { - { 2880, 576, 108000, 256, 48, 272, 5, 5, 39, + { 2880, 576, 108000000, 256, 48, 272, 5, 5, 39, OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, false, }, { 37, HDMI_HDMI }, @@ -117,121 +117,121 @@ static const struct hdmi_config cea_timings[] = { static const struct hdmi_config vesa_timings[] = { /* VESA From Here */ { - { 640, 480, 25175, 96, 16, 48, 2, 11, 31, + { 640, 480, 25175000, 96, 16, 48, 2, 11, 31, OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, false, }, { 4, HDMI_DVI }, }, { - { 800, 600, 40000, 128, 40, 88, 4, 1, 23, + { 800, 600, 40000000, 128, 40, 88, 4, 1, 23, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, false, }, { 9, HDMI_DVI }, }, { - { 848, 480, 33750, 112, 16, 112, 8, 6, 23, + { 848, 480, 33750000, 112, 16, 112, 8, 6, 23, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, false, }, { 0xE, HDMI_DVI }, }, { - { 1280, 768, 79500, 128, 64, 192, 7, 3, 20, + { 1280, 768, 79500000, 128, 64, 192, 7, 3, 20, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, false, }, { 0x17, HDMI_DVI }, }, { - { 1280, 800, 83500, 128, 72, 200, 6, 3, 22, + { 1280, 800, 83500000, 128, 72, 200, 6, 3, 22, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, false, }, { 0x1C, HDMI_DVI }, }, { - { 1360, 768, 85500, 112, 64, 256, 6, 3, 18, + { 1360, 768, 85500000, 112, 64, 256, 6, 3, 18, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, false, }, { 0x27, HDMI_DVI }, }, { - { 1280, 960, 108000, 112, 96, 312, 3, 1, 36, + { 1280, 960, 108000000, 112, 96, 312, 3, 1, 36, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, false, }, { 0x20, HDMI_DVI }, }, { - { 1280, 1024, 108000, 112, 48, 248, 3, 1, 38, + { 1280, 1024, 108000000, 112, 48, 248, 3, 1, 38, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, false, }, { 0x23, HDMI_DVI }, }, { - { 1024, 768, 65000, 136, 24, 160, 6, 3, 29, + { 1024, 768, 65000000, 136, 24, 160, 6, 3, 29, OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, false, }, { 0x10, HDMI_DVI }, }, { - { 1400, 1050, 121750, 144, 88, 232, 4, 3, 32, + { 1400, 1050, 121750000, 144, 88, 232, 4, 3, 32, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, false, }, { 0x2A, HDMI_DVI }, }, { - { 1440, 900, 106500, 152, 80, 232, 6, 3, 25, + { 1440, 900, 106500000, 152, 80, 232, 6, 3, 25, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, false, }, { 0x2F, HDMI_DVI }, }, { - { 1680, 1050, 146250, 176 , 104, 280, 6, 3, 30, + { 1680, 1050, 146250000, 176 , 104, 280, 6, 3, 30, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, false, }, { 0x3A, HDMI_DVI }, }, { - { 1366, 768, 85500, 143, 70, 213, 3, 3, 24, + { 1366, 768, 85500000, 143, 70, 213, 3, 3, 24, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, false, }, { 0x51, HDMI_DVI }, }, { - { 1920, 1080, 148500, 44, 148, 80, 5, 4, 36, + { 1920, 1080, 148500000, 44, 148, 80, 5, 4, 36, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, false, }, { 0x52, HDMI_DVI }, }, { - { 1280, 768, 68250, 32, 48, 80, 7, 3, 12, + { 1280, 768, 68250000, 32, 48, 80, 7, 3, 12, OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, false, }, { 0x16, HDMI_DVI }, }, { - { 1400, 1050, 101000, 32, 48, 80, 4, 3, 23, + { 1400, 1050, 101000000, 32, 48, 80, 4, 3, 23, OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, false, }, { 0x29, HDMI_DVI }, }, { - { 1680, 1050, 119000, 32, 48, 80, 6, 3, 21, + { 1680, 1050, 119000000, 32, 48, 80, 6, 3, 21, OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, false, }, { 0x39, HDMI_DVI }, }, { - { 1280, 800, 79500, 32, 48, 80, 6, 3, 14, + { 1280, 800, 79500000, 32, 48, 80, 6, 3, 14, OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, false, }, { 0x1B, HDMI_DVI }, }, { - { 1280, 720, 74250, 40, 110, 220, 5, 5, 20, + { 1280, 720, 74250000, 40, 110, 220, 5, 5, 20, OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, false, }, { 0x55, HDMI_DVI }, }, { - { 1920, 1200, 154000, 32, 48, 80, 6, 3, 26, + { 1920, 1200, 154000000, 32, 48, 80, 6, 3, 26, OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, false, }, { 0x44, HDMI_DVI }, @@ -277,8 +277,8 @@ static bool hdmi_timings_compare(struct omap_video_timings *timing1, { int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync; - if ((DIV_ROUND_CLOSEST(timing2->pixel_clock, 1000) == - DIV_ROUND_CLOSEST(timing1->pixel_clock, 1000)) && + if ((DIV_ROUND_CLOSEST(timing2->pixelclock, 1000000) == + DIV_ROUND_CLOSEST(timing1->pixelclock, 1000000)) && (timing2->x_res == timing1->x_res) && (timing2->y_res == timing1->y_res)) { diff --git a/drivers/video/omap2/dss/hdmi_wp.c b/drivers/video/omap2/dss/hdmi_wp.c index cd620c6e43a0..f5f4ccf50d90 100644 --- a/drivers/video/omap2/dss/hdmi_wp.c +++ b/drivers/video/omap2/dss/hdmi_wp.c @@ -171,6 +171,8 @@ void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt, video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444; video_fmt->y_res = param->timings.y_res; video_fmt->x_res = param->timings.x_res; + if (param->timings.interlace) + video_fmt->y_res /= 2; timings->hbp = param->timings.hbp; timings->hfp = param->timings.hfp; diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index efb9ee9e3c96..911dcc9173a6 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -26,6 +26,7 @@ #include <linux/export.h> #include <linux/platform_device.h> #include <linux/string.h> +#include <linux/of.h> #include <video/omapdss.h> #include "dss.h" @@ -41,12 +42,14 @@ static struct { int datapairs; struct omap_dss_device output; + + bool port_initialized; } sdi; struct sdi_clk_calc_ctx { unsigned long pck_min, pck_max; - unsigned long long fck; + unsigned long fck; struct dispc_clock_info dispc_cinfo; }; @@ -149,20 +152,19 @@ static int sdi_display_enable(struct omap_dss_device *dssdev) t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; - r = sdi_calc_clock_div(t->pixel_clock * 1000, &fck, &dispc_cinfo); + r = sdi_calc_clock_div(t->pixelclock, &fck, &dispc_cinfo); if (r) goto err_calc_clock_div; sdi.mgr_config.clock_info = dispc_cinfo; - pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div / 1000; + pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div; - if (pck != t->pixel_clock) { - DSSWARN("Could not find exact pixel clock. Requested %d kHz, " - "got %lu kHz\n", - t->pixel_clock, pck); + if (pck != t->pixelclock) { + DSSWARN("Could not find exact pixel clock. Requested %d Hz, got %lu Hz\n", + t->pixelclock, pck); - t->pixel_clock = pck; + t->pixelclock = pck; } @@ -244,7 +246,7 @@ static int sdi_check_timings(struct omap_dss_device *dssdev, if (mgr && !dispc_mgr_timings_ok(mgr->id, timings)) return -EINVAL; - if (timings->pixel_clock == 0) + if (timings->pixelclock == 0) return -EINVAL; return 0; @@ -387,3 +389,45 @@ void __exit sdi_uninit_platform_driver(void) { platform_driver_unregister(&omap_sdi_driver); } + +int __init sdi_init_port(struct platform_device *pdev, struct device_node *port) +{ + struct device_node *ep; + u32 datapairs; + int r; + + ep = omapdss_of_get_next_endpoint(port, NULL); + if (!ep) + return 0; + + r = of_property_read_u32(ep, "datapairs", &datapairs); + if (r) { + DSSERR("failed to parse datapairs\n"); + goto err_datapairs; + } + + sdi.datapairs = datapairs; + + of_node_put(ep); + + sdi.pdev = pdev; + + sdi_init_output(pdev); + + sdi.port_initialized = true; + + return 0; + +err_datapairs: + of_node_put(ep); + + return r; +} + +void __exit sdi_uninit_port(void) +{ + if (!sdi.port_initialized) + return; + + sdi_uninit_output(sdi.pdev); +} diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 2cd7f7e42105..21d81113962b 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -34,6 +34,7 @@ #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/pm_runtime.h> +#include <linux/of.h> #include <video/omapdss.h> @@ -264,7 +265,7 @@ static const struct venc_config venc_config_pal_bdghi = { const struct omap_video_timings omap_dss_pal_timings = { .x_res = 720, .y_res = 574, - .pixel_clock = 13500, + .pixelclock = 13500000, .hsw = 64, .hfp = 12, .hbp = 68, @@ -279,7 +280,7 @@ EXPORT_SYMBOL(omap_dss_pal_timings); const struct omap_video_timings omap_dss_ntsc_timings = { .x_res = 720, .y_res = 482, - .pixel_clock = 13500, + .pixelclock = 13500000, .hsw = 64, .hfp = 16, .hbp = 58, @@ -636,7 +637,10 @@ static int venc_init_regulator(void) if (venc.vdda_dac_reg != NULL) return 0; - vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda_dac"); + if (venc.pdev->dev.of_node) + vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda"); + else + vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda_dac"); if (IS_ERR(vdda_dac)) { if (PTR_ERR(vdda_dac) != -EPROBE_DEFER) @@ -805,6 +809,48 @@ static void __exit venc_uninit_output(struct platform_device *pdev) omapdss_unregister_output(out); } +static int venc_probe_of(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct device_node *ep; + u32 channels; + int r; + + ep = omapdss_of_get_first_endpoint(node); + if (!ep) + return 0; + + venc.invert_polarity = of_property_read_bool(ep, "ti,invert-polarity"); + + r = of_property_read_u32(ep, "ti,channels", &channels); + if (r) { + dev_err(&pdev->dev, + "failed to read property 'ti,channels': %d\n", r); + goto err; + } + + switch (channels) { + case 1: + venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE; + break; + case 2: + venc.type = OMAP_DSS_VENC_TYPE_SVIDEO; + break; + default: + dev_err(&pdev->dev, "bad channel propert '%d'\n", channels); + r = -EINVAL; + goto err; + } + + of_node_put(ep); + + return 0; +err: + of_node_put(ep); + + return 0; +} + /* VENC HW IP initialisation */ static int omap_venchw_probe(struct platform_device *pdev) { @@ -846,12 +892,21 @@ static int omap_venchw_probe(struct platform_device *pdev) venc_runtime_put(); + if (pdev->dev.of_node) { + r = venc_probe_of(pdev); + if (r) { + DSSERR("Invalid DT data\n"); + goto err_probe_of; + } + } + dss_debugfs_create_file("venc", venc_dump_regs); venc_init_output(pdev); return 0; +err_probe_of: err_runtime_get: pm_runtime_disable(&pdev->dev); return r; @@ -895,6 +950,14 @@ static const struct dev_pm_ops venc_pm_ops = { .runtime_resume = venc_runtime_resume, }; + +static const struct of_device_id venc_of_match[] = { + { .compatible = "ti,omap2-venc", }, + { .compatible = "ti,omap3-venc", }, + { .compatible = "ti,omap4-venc", }, + {}, +}; + static struct platform_driver omap_venchw_driver = { .probe = omap_venchw_probe, .remove = __exit_p(omap_venchw_remove), @@ -902,6 +965,7 @@ static struct platform_driver omap_venchw_driver = { .name = "omapdss_venc", .owner = THIS_MODULE, .pm = &venc_pm_ops, + .of_match_table = venc_of_match, }, }; diff --git a/drivers/video/omap2/dss/venc_panel.c b/drivers/video/omap2/dss/venc_panel.c index f7d92c57bd73..af68cd444d7e 100644 --- a/drivers/video/omap2/dss/venc_panel.c +++ b/drivers/video/omap2/dss/venc_panel.c @@ -89,7 +89,7 @@ static int venc_panel_probe(struct omap_dss_device *dssdev) const struct omap_video_timings default_timings = { .x_res = 720, .y_res = 574, - .pixel_clock = 13500, + .pixelclock = 13500000, .hsw = 64, .hfp = 12, .hbp = 68, diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index fcb9e932d00c..ec2d132c782d 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -723,8 +723,8 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var) display->driver->get_timings(display, &timings); /* pixclock in ps, the rest in pixclock */ - var->pixclock = timings.pixel_clock != 0 ? - KHZ2PICOS(timings.pixel_clock) : + var->pixclock = timings.pixelclock != 0 ? + KHZ2PICOS(timings.pixelclock / 1000) : 0; var->left_margin = timings.hbp; var->right_margin = timings.hfp; @@ -2077,7 +2077,7 @@ static int omapfb_mode_to_timings(const char *mode_str, timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; } - timings->pixel_clock = PICOS2KHZ(var->pixclock); + timings->pixelclock = PICOS2KHZ(var->pixclock) * 1000; timings->hbp = var->left_margin; timings->hfp = var->right_margin; timings->vbp = var->upper_margin; @@ -2229,7 +2229,7 @@ static void fb_videomode_to_omap_timings(struct fb_videomode *m, t->x_res = m->xres; t->y_res = m->yres; - t->pixel_clock = PICOS2KHZ(m->pixclock); + t->pixelclock = PICOS2KHZ(m->pixclock) * 1000; t->hsw = m->hsync_len; t->hfp = m->right_margin; t->hbp = m->left_margin; @@ -2417,6 +2417,55 @@ static int omapfb_init_connections(struct omapfb2_device *fbdev, return 0; } +static struct omap_dss_device * +omapfb_find_default_display(struct omapfb2_device *fbdev) +{ + const char *def_name; + int i; + + /* + * Search with the display name from the user or the board file, + * comparing to display names and aliases + */ + + def_name = omapdss_get_default_display_name(); + + if (def_name) { + for (i = 0; i < fbdev->num_displays; ++i) { + struct omap_dss_device *dssdev; + + dssdev = fbdev->displays[i].dssdev; + + if (dssdev->name && strcmp(def_name, dssdev->name) == 0) + return dssdev; + + if (strcmp(def_name, dssdev->alias) == 0) + return dssdev; + } + + /* def_name given but not found */ + return NULL; + } + + /* then look for DT alias display0 */ + for (i = 0; i < fbdev->num_displays; ++i) { + struct omap_dss_device *dssdev; + int id; + + dssdev = fbdev->displays[i].dssdev; + + if (dssdev->dev->of_node == NULL) + continue; + + id = of_alias_get_id(dssdev->dev->of_node, "display"); + if (id == 0) + return dssdev; + } + + /* return the first display we have in the list */ + return fbdev->displays[0].dssdev; +} + static int omapfb_probe(struct platform_device *pdev) { struct omapfb2_device *fbdev = NULL; @@ -2494,23 +2543,7 @@ static int omapfb_probe(struct platform_device *pdev) for (i = 0; i < fbdev->num_managers; i++) fbdev->managers[i] = omap_dss_get_overlay_manager(i); - def_display = NULL; - - for (i = 0; i < fbdev->num_displays; ++i) { - struct omap_dss_device *dssdev; - const char *def_name; - - def_name = omapdss_get_default_display_name(); - - dssdev = fbdev->displays[i].dssdev; - - if (def_name == NULL || - (dssdev->name && strcmp(def_name, dssdev->name) == 0)) { - def_display = dssdev; - break; - } - } - + def_display = omapfb_find_default_display(fbdev); if (def_display == NULL) { dev_err(fbdev->dev, "failed to find default display\n"); r = -EPROBE_DEFER; diff --git a/drivers/video/output.c b/drivers/video/output.c deleted file mode 100644 index 1446c49fe6af..000000000000 --- a/drivers/video/output.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * output.c - Display Output Switch driver - * - * Copyright (C) 2006 Luming Yu <luming.yu@intel.com> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ -#include <linux/module.h> -#include <linux/video_output.h> -#include <linux/slab.h> -#include <linux/err.h> -#include <linux/ctype.h> - - -MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Luming Yu <luming.yu@intel.com>"); - -static ssize_t state_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - ssize_t ret_size = 0; - struct output_device *od = to_output_device(dev); - if (od->props) - ret_size = sprintf(buf,"%.8x\n",od->props->get_status(od)); - return ret_size; -} - -static ssize_t state_store(struct device *dev, struct device_attribute *attr, - const char *buf,size_t count) -{ - char *endp; - struct output_device *od = to_output_device(dev); - int request_state = simple_strtoul(buf,&endp,0); - size_t size = endp - buf; - - if (isspace(*endp)) - size++; - if (size != count) - return -EINVAL; - - if (od->props) { - od->request_state = request_state; - od->props->set_state(od); - } - return count; -} -static DEVICE_ATTR_RW(state); - -static void video_output_release(struct device *dev) -{ - struct output_device *od = to_output_device(dev); - kfree(od); -} - -static struct attribute *video_output_attrs[] = { - &dev_attr_state.attr, - NULL, -}; -ATTRIBUTE_GROUPS(video_output); - -static struct class video_output_class = { - .name = "video_output", - .dev_release = video_output_release, - .dev_groups = video_output_groups, -}; - -struct output_device *video_output_register(const char *name, - struct device *dev, - void *devdata, - struct output_properties *op) -{ - struct output_device *new_dev; - int ret_code = 0; - - new_dev = kzalloc(sizeof(struct output_device),GFP_KERNEL); - if (!new_dev) { - ret_code = -ENOMEM; - goto error_return; - } - new_dev->props = op; - new_dev->dev.class = &video_output_class; - new_dev->dev.parent = dev; - dev_set_name(&new_dev->dev, "%s", name); - dev_set_drvdata(&new_dev->dev, devdata); - ret_code = device_register(&new_dev->dev); - if (ret_code) { - kfree(new_dev); - goto error_return; - } - return new_dev; - -error_return: - return ERR_PTR(ret_code); -} -EXPORT_SYMBOL(video_output_register); - -void video_output_unregister(struct output_device *dev) -{ - if (!dev) - return; - device_unregister(&dev->dev); -} -EXPORT_SYMBOL(video_output_unregister); - -static void __exit video_output_class_exit(void) -{ - class_unregister(&video_output_class); -} - -static int __init video_output_class_init(void) -{ - return class_register(&video_output_class); -} - -postcore_initcall(video_output_class_init); -module_exit(video_output_class_exit); diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c index ad382b3396cd..417f9a27eb7d 100644 --- a/drivers/video/pxa3xx-gcu.c +++ b/drivers/video/pxa3xx-gcu.c @@ -107,7 +107,6 @@ struct pxa3xx_gcu_priv { struct timeval base_time; struct pxa3xx_gcu_batch *free; - struct pxa3xx_gcu_batch *ready; struct pxa3xx_gcu_batch *ready_last; struct pxa3xx_gcu_batch *running; @@ -368,27 +367,35 @@ pxa3xx_gcu_wait_free(struct pxa3xx_gcu_priv *priv) /* Misc device layer */ -static inline struct pxa3xx_gcu_priv *file_dev(struct file *file) +static inline struct pxa3xx_gcu_priv *to_pxa3xx_gcu_priv(struct file *file) { struct miscdevice *dev = file->private_data; return container_of(dev, struct pxa3xx_gcu_priv, misc_dev); } +/* + * provide an empty .open callback, so the core sets file->private_data + * for us. + */ +static int pxa3xx_gcu_open(struct inode *inode, struct file *file) +{ + return 0; +} + static ssize_t -pxa3xx_gcu_misc_write(struct file *file, const char *buff, - size_t count, loff_t *offp) +pxa3xx_gcu_write(struct file *file, const char *buff, + size_t count, loff_t *offp) { int ret; unsigned long flags; struct pxa3xx_gcu_batch *buffer; - struct pxa3xx_gcu_priv *priv = file_dev(file); + struct pxa3xx_gcu_priv *priv = to_pxa3xx_gcu_priv(file); int words = count / 4; /* Does not need to be atomic. There's a lock in user space, * but anyhow, this is just for statistics. */ priv->shared->num_writes++; - priv->shared->num_words += words; /* Last word reserved for batch buffer end command */ @@ -406,10 +413,8 @@ pxa3xx_gcu_misc_write(struct file *file, const char *buff, * Get buffer from free list */ spin_lock_irqsave(&priv->spinlock, flags); - buffer = priv->free; priv->free = buffer->next; - spin_unlock_irqrestore(&priv->spinlock, flags); @@ -454,10 +459,10 @@ pxa3xx_gcu_misc_write(struct file *file, const char *buff, static long -pxa3xx_gcu_misc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +pxa3xx_gcu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { unsigned long flags; - struct pxa3xx_gcu_priv *priv = file_dev(file); + struct pxa3xx_gcu_priv *priv = to_pxa3xx_gcu_priv(file); switch (cmd) { case PXA3XX_GCU_IOCTL_RESET: @@ -474,10 +479,10 @@ pxa3xx_gcu_misc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } static int -pxa3xx_gcu_misc_mmap(struct file *file, struct vm_area_struct *vma) +pxa3xx_gcu_mmap(struct file *file, struct vm_area_struct *vma) { unsigned int size = vma->vm_end - vma->vm_start; - struct pxa3xx_gcu_priv *priv = file_dev(file); + struct pxa3xx_gcu_priv *priv = to_pxa3xx_gcu_priv(file); switch (vma->vm_pgoff) { case 0: @@ -532,8 +537,8 @@ static inline void pxa3xx_gcu_init_debug_timer(void) {} #endif static int -add_buffer(struct platform_device *dev, - struct pxa3xx_gcu_priv *priv) +pxa3xx_gcu_add_buffer(struct device *dev, + struct pxa3xx_gcu_priv *priv) { struct pxa3xx_gcu_batch *buffer; @@ -541,7 +546,7 @@ add_buffer(struct platform_device *dev, if (!buffer) return -ENOMEM; - buffer->ptr = dma_alloc_coherent(&dev->dev, PXA3XX_GCU_BATCH_WORDS * 4, + buffer->ptr = dma_alloc_coherent(dev, PXA3XX_GCU_BATCH_WORDS * 4, &buffer->phys, GFP_KERNEL); if (!buffer->ptr) { kfree(buffer); @@ -549,57 +554,49 @@ add_buffer(struct platform_device *dev, } buffer->next = priv->free; - priv->free = buffer; return 0; } static void -free_buffers(struct platform_device *dev, - struct pxa3xx_gcu_priv *priv) +pxa3xx_gcu_free_buffers(struct device *dev, + struct pxa3xx_gcu_priv *priv) { struct pxa3xx_gcu_batch *next, *buffer = priv->free; while (buffer) { next = buffer->next; - dma_free_coherent(&dev->dev, PXA3XX_GCU_BATCH_WORDS * 4, + dma_free_coherent(dev, PXA3XX_GCU_BATCH_WORDS * 4, buffer->ptr, buffer->phys); kfree(buffer); - buffer = next; } priv->free = NULL; } -static const struct file_operations misc_fops = { - .owner = THIS_MODULE, - .write = pxa3xx_gcu_misc_write, - .unlocked_ioctl = pxa3xx_gcu_misc_ioctl, - .mmap = pxa3xx_gcu_misc_mmap +static const struct file_operations pxa3xx_gcu_miscdev_fops = { + .owner = THIS_MODULE, + .open = pxa3xx_gcu_open, + .write = pxa3xx_gcu_write, + .unlocked_ioctl = pxa3xx_gcu_ioctl, + .mmap = pxa3xx_gcu_mmap, }; -static int pxa3xx_gcu_probe(struct platform_device *dev) +static int pxa3xx_gcu_probe(struct platform_device *pdev) { int i, ret, irq; struct resource *r; struct pxa3xx_gcu_priv *priv; + struct device *dev = &pdev->dev; - priv = kzalloc(sizeof(struct pxa3xx_gcu_priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(struct pxa3xx_gcu_priv), GFP_KERNEL); if (!priv) return -ENOMEM; - for (i = 0; i < 8; i++) { - ret = add_buffer(dev, priv); - if (ret) { - dev_err(&dev->dev, "failed to allocate DMA memory\n"); - goto err_free_priv; - } - } - init_waitqueue_head(&priv->wait_idle); init_waitqueue_head(&priv->wait_free); spin_lock_init(&priv->spinlock); @@ -611,125 +608,99 @@ static int pxa3xx_gcu_probe(struct platform_device *dev) priv->misc_dev.minor = MISCDEV_MINOR, priv->misc_dev.name = DRV_NAME, - priv->misc_dev.fops = &misc_fops, + priv->misc_dev.fops = &pxa3xx_gcu_miscdev_fops; - /* register misc device */ - ret = misc_register(&priv->misc_dev); - if (ret < 0) { - dev_err(&dev->dev, "misc_register() for minor %d failed\n", - MISCDEV_MINOR); - goto err_free_priv; + /* handle IO resources */ + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->mmio_base = devm_request_and_ioremap(dev, r); + if (IS_ERR(priv->mmio_base)) { + dev_err(dev, "failed to map I/O memory\n"); + return PTR_ERR(priv->mmio_base); } - /* handle IO resources */ - r = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (r == NULL) { - dev_err(&dev->dev, "no I/O memory resource defined\n"); - ret = -ENODEV; - goto err_misc_deregister; + /* enable the clock */ + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(dev, "failed to get clock\n"); + return PTR_ERR(priv->clk); } - if (!request_mem_region(r->start, resource_size(r), dev->name)) { - dev_err(&dev->dev, "failed to request I/O memory\n"); - ret = -EBUSY; - goto err_misc_deregister; + /* request the IRQ */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "no IRQ defined\n"); + return -ENODEV; } - priv->mmio_base = ioremap_nocache(r->start, resource_size(r)); - if (!priv->mmio_base) { - dev_err(&dev->dev, "failed to map I/O memory\n"); - ret = -EBUSY; - goto err_free_mem_region; + ret = devm_request_irq(dev, irq, pxa3xx_gcu_handle_irq, + 0, DRV_NAME, priv); + if (ret < 0) { + dev_err(dev, "request_irq failed\n"); + return ret; } /* allocate dma memory */ - priv->shared = dma_alloc_coherent(&dev->dev, SHARED_SIZE, + priv->shared = dma_alloc_coherent(dev, SHARED_SIZE, &priv->shared_phys, GFP_KERNEL); - if (!priv->shared) { - dev_err(&dev->dev, "failed to allocate DMA memory\n"); - ret = -ENOMEM; - goto err_free_io; + dev_err(dev, "failed to allocate DMA memory\n"); + return -ENOMEM; } - /* enable the clock */ - priv->clk = clk_get(&dev->dev, NULL); - if (IS_ERR(priv->clk)) { - dev_err(&dev->dev, "failed to get clock\n"); - ret = -ENODEV; + /* register misc device */ + ret = misc_register(&priv->misc_dev); + if (ret < 0) { + dev_err(dev, "misc_register() for minor %d failed\n", + MISCDEV_MINOR); goto err_free_dma; } ret = clk_enable(priv->clk); if (ret < 0) { - dev_err(&dev->dev, "failed to enable clock\n"); - goto err_put_clk; - } - - /* request the IRQ */ - irq = platform_get_irq(dev, 0); - if (irq < 0) { - dev_err(&dev->dev, "no IRQ defined\n"); - ret = -ENODEV; - goto err_put_clk; + dev_err(dev, "failed to enable clock\n"); + goto err_misc_deregister; } - ret = request_irq(irq, pxa3xx_gcu_handle_irq, - 0, DRV_NAME, priv); - if (ret) { - dev_err(&dev->dev, "request_irq failed\n"); - ret = -EBUSY; - goto err_put_clk; + for (i = 0; i < 8; i++) { + ret = pxa3xx_gcu_add_buffer(dev, priv); + if (ret) { + dev_err(dev, "failed to allocate DMA memory\n"); + goto err_disable_clk; + } } - platform_set_drvdata(dev, priv); + platform_set_drvdata(pdev, priv); priv->resource_mem = r; pxa3xx_gcu_reset(priv); pxa3xx_gcu_init_debug_timer(); - dev_info(&dev->dev, "registered @0x%p, DMA 0x%p (%d bytes), IRQ %d\n", + dev_info(dev, "registered @0x%p, DMA 0x%p (%d bytes), IRQ %d\n", (void *) r->start, (void *) priv->shared_phys, SHARED_SIZE, irq); return 0; -err_put_clk: - clk_disable(priv->clk); - clk_put(priv->clk); - err_free_dma: - dma_free_coherent(&dev->dev, SHARED_SIZE, + dma_free_coherent(dev, SHARED_SIZE, priv->shared, priv->shared_phys); -err_free_io: - iounmap(priv->mmio_base); - -err_free_mem_region: - release_mem_region(r->start, resource_size(r)); - err_misc_deregister: misc_deregister(&priv->misc_dev); -err_free_priv: - free_buffers(dev, priv); - kfree(priv); +err_disable_clk: + clk_disable(priv->clk); + return ret; } -static int pxa3xx_gcu_remove(struct platform_device *dev) +static int pxa3xx_gcu_remove(struct platform_device *pdev) { - struct pxa3xx_gcu_priv *priv = platform_get_drvdata(dev); - struct resource *r = priv->resource_mem; + struct pxa3xx_gcu_priv *priv = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; pxa3xx_gcu_wait_idle(priv); - misc_deregister(&priv->misc_dev); - dma_free_coherent(&dev->dev, SHARED_SIZE, - priv->shared, priv->shared_phys); - iounmap(priv->mmio_base); - release_mem_region(r->start, resource_size(r)); - clk_disable(priv->clk); - free_buffers(dev, priv); - kfree(priv); + dma_free_coherent(dev, SHARED_SIZE, priv->shared, priv->shared_phys); + pxa3xx_gcu_free_buffers(dev, priv); return 0; } diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c deleted file mode 100644 index bc74d0408998..000000000000 --- a/drivers/video/sgivwfb.c +++ /dev/null @@ -1,889 +0,0 @@ -/* - * linux/drivers/video/sgivwfb.c -- SGI DBE frame buffer device - * - * Copyright (C) 1999 Silicon Graphics, Inc. - * Jeffrey Newquist, newquist@engr.sgi.som - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/errno.h> -#include <linux/delay.h> -#include <linux/fb.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/platform_device.h> - -#include <asm/io.h> -#include <asm/mtrr.h> -#include <asm/visws/sgivw.h> - -#define INCLUDE_TIMING_TABLE_DATA -#define DBE_REG_BASE par->regs -#include <video/sgivw.h> - -struct sgivw_par { - struct asregs *regs; - u32 cmap_fifo; - u_long timing_num; -}; - -#define FLATPANEL_SGI_1600SW 5 - -/* - * RAM we reserve for the frame buffer. This defines the maximum screen - * size - * - * The default can be overridden if the driver is compiled as a module - */ - -static int ypan = 0; -static int ywrap = 0; - -static int flatpanel_id = -1; - -static struct fb_fix_screeninfo sgivwfb_fix = { - .id = "SGI Vis WS FB", - .type = FB_TYPE_PACKED_PIXELS, - .visual = FB_VISUAL_PSEUDOCOLOR, - .mmio_start = DBE_REG_PHYS, - .mmio_len = DBE_REG_SIZE, - .accel = FB_ACCEL_NONE, - .line_length = 640, -}; - -static struct fb_var_screeninfo sgivwfb_var = { - /* 640x480, 8 bpp */ - .xres = 640, - .yres = 480, - .xres_virtual = 640, - .yres_virtual = 480, - .bits_per_pixel = 8, - .red = { 0, 8, 0 }, - .green = { 0, 8, 0 }, - .blue = { 0, 8, 0 }, - .height = -1, - .width = -1, - .pixclock = 20000, - .left_margin = 64, - .right_margin = 64, - .upper_margin = 32, - .lower_margin = 32, - .hsync_len = 64, - .vsync_len = 2, - .vmode = FB_VMODE_NONINTERLACED -}; - -static struct fb_var_screeninfo sgivwfb_var1600sw = { - /* 1600x1024, 8 bpp */ - .xres = 1600, - .yres = 1024, - .xres_virtual = 1600, - .yres_virtual = 1024, - .bits_per_pixel = 8, - .red = { 0, 8, 0 }, - .green = { 0, 8, 0 }, - .blue = { 0, 8, 0 }, - .height = -1, - .width = -1, - .pixclock = 9353, - .left_margin = 20, - .right_margin = 30, - .upper_margin = 37, - .lower_margin = 3, - .hsync_len = 20, - .vsync_len = 3, - .vmode = FB_VMODE_NONINTERLACED -}; - -/* - * Interface used by the world - */ -int sgivwfb_init(void); - -static int sgivwfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info); -static int sgivwfb_set_par(struct fb_info *info); -static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green, - u_int blue, u_int transp, - struct fb_info *info); -static int sgivwfb_mmap(struct fb_info *info, - struct vm_area_struct *vma); - -static struct fb_ops sgivwfb_ops = { - .owner = THIS_MODULE, - .fb_check_var = sgivwfb_check_var, - .fb_set_par = sgivwfb_set_par, - .fb_setcolreg = sgivwfb_setcolreg, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_mmap = sgivwfb_mmap, -}; - -/* - * Internal routines - */ -static unsigned long bytes_per_pixel(int bpp) -{ - switch (bpp) { - case 8: - return 1; - case 16: - return 2; - case 32: - return 4; - default: - printk(KERN_INFO "sgivwfb: unsupported bpp %d\n", bpp); - return 0; - } -} - -static unsigned long get_line_length(int xres_virtual, int bpp) -{ - return (xres_virtual * bytes_per_pixel(bpp)); -} - -/* - * Function: dbe_TurnOffDma - * Parameters: (None) - * Description: This should turn off the monitor and dbe. This is used - * when switching between the serial console and the graphics - * console. - */ - -static void dbe_TurnOffDma(struct sgivw_par *par) -{ - unsigned int readVal; - int i; - - // Check to see if things are already turned off: - // 1) Check to see if dbe is not using the internal dotclock. - // 2) Check to see if the xy counter in dbe is already off. - - DBE_GETREG(ctrlstat, readVal); - if (GET_DBE_FIELD(CTRLSTAT, PCLKSEL, readVal) < 2) - return; - - DBE_GETREG(vt_xy, readVal); - if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1) - return; - - // Otherwise, turn off dbe - - DBE_GETREG(ovr_control, readVal); - SET_DBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, readVal, 0); - DBE_SETREG(ovr_control, readVal); - udelay(1000); - DBE_GETREG(frm_control, readVal); - SET_DBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, readVal, 0); - DBE_SETREG(frm_control, readVal); - udelay(1000); - DBE_GETREG(did_control, readVal); - SET_DBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, readVal, 0); - DBE_SETREG(did_control, readVal); - udelay(1000); - - // XXX HACK: - // - // This was necessary for GBE--we had to wait through two - // vertical retrace periods before the pixel DMA was - // turned off for sure. I've left this in for now, in - // case dbe needs it. - - for (i = 0; i < 10000; i++) { - DBE_GETREG(frm_inhwctrl, readVal); - if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) == - 0) - udelay(10); - else { - DBE_GETREG(ovr_inhwctrl, readVal); - if (GET_DBE_FIELD - (OVR_INHWCTRL, OVR_DMA_ENABLE, readVal) == 0) - udelay(10); - else { - DBE_GETREG(did_inhwctrl, readVal); - if (GET_DBE_FIELD - (DID_INHWCTRL, DID_DMA_ENABLE, - readVal) == 0) - udelay(10); - else - break; - } - } - } -} - -/* - * Set the User Defined Part of the Display. Again if par use it to get - * real video mode. - */ -static int sgivwfb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - struct sgivw_par *par = (struct sgivw_par *)info->par; - struct dbe_timing_info *timing; - u_long line_length; - u_long min_mode; - int req_dot; - int test_mode; - - /* - * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! - * as FB_VMODE_SMOOTH_XPAN is only used internally - */ - - if (var->vmode & FB_VMODE_CONUPDATE) { - var->vmode |= FB_VMODE_YWRAP; - var->xoffset = info->var.xoffset; - var->yoffset = info->var.yoffset; - } - - /* XXX FIXME - forcing var's */ - var->xoffset = 0; - var->yoffset = 0; - - /* Limit bpp to 8, 16, and 32 */ - if (var->bits_per_pixel <= 8) - var->bits_per_pixel = 8; - else if (var->bits_per_pixel <= 16) - var->bits_per_pixel = 16; - else if (var->bits_per_pixel <= 32) - var->bits_per_pixel = 32; - else - return -EINVAL; - - var->grayscale = 0; /* No grayscale for now */ - - /* determine valid resolution and timing */ - for (min_mode = 0; min_mode < ARRAY_SIZE(dbeVTimings); min_mode++) { - if (dbeVTimings[min_mode].width >= var->xres && - dbeVTimings[min_mode].height >= var->yres) - break; - } - - if (min_mode == ARRAY_SIZE(dbeVTimings)) - return -EINVAL; /* Resolution to high */ - - /* XXX FIXME - should try to pick best refresh rate */ - /* for now, pick closest dot-clock within 3MHz */ - req_dot = PICOS2KHZ(var->pixclock); - printk(KERN_INFO "sgivwfb: requested pixclock=%d ps (%d KHz)\n", - var->pixclock, req_dot); - test_mode = min_mode; - while (dbeVTimings[min_mode].width == dbeVTimings[test_mode].width) { - if (dbeVTimings[test_mode].cfreq + 3000 > req_dot) - break; - test_mode++; - } - if (dbeVTimings[min_mode].width != dbeVTimings[test_mode].width) - test_mode--; - min_mode = test_mode; - timing = &dbeVTimings[min_mode]; - printk(KERN_INFO "sgivwfb: granted dot-clock=%d KHz\n", timing->cfreq); - - /* Adjust virtual resolution, if necessary */ - if (var->xres > var->xres_virtual || (!ywrap && !ypan)) - var->xres_virtual = var->xres; - if (var->yres > var->yres_virtual || (!ywrap && !ypan)) - var->yres_virtual = var->yres; - - /* - * Memory limit - */ - line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); - if (line_length * var->yres_virtual > sgivwfb_mem_size) - return -ENOMEM; /* Virtual resolution to high */ - - info->fix.line_length = line_length; - - switch (var->bits_per_pixel) { - case 8: - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 0; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - break; - case 16: /* RGBA 5551 */ - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 6; - var->green.length = 5; - var->blue.offset = 1; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - break; - case 32: /* RGB 8888 */ - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 16; - var->blue.length = 8; - var->transp.offset = 24; - var->transp.length = 8; - break; - } - var->red.msb_right = 0; - var->green.msb_right = 0; - var->blue.msb_right = 0; - var->transp.msb_right = 0; - - /* set video timing information */ - var->pixclock = KHZ2PICOS(timing->cfreq); - var->left_margin = timing->htotal - timing->hsync_end; - var->right_margin = timing->hsync_start - timing->width; - var->upper_margin = timing->vtotal - timing->vsync_end; - var->lower_margin = timing->vsync_start - timing->height; - var->hsync_len = timing->hsync_end - timing->hsync_start; - var->vsync_len = timing->vsync_end - timing->vsync_start; - - /* Ouch. This breaks the rules but timing_num is only important if you - * change a video mode */ - par->timing_num = min_mode; - - printk(KERN_INFO "sgivwfb: new video mode xres=%d yres=%d bpp=%d\n", - var->xres, var->yres, var->bits_per_pixel); - printk(KERN_INFO " vxres=%d vyres=%d\n", var->xres_virtual, - var->yres_virtual); - return 0; -} - -/* - * Setup flatpanel related registers. - */ -static void sgivwfb_setup_flatpanel(struct sgivw_par *par, struct dbe_timing_info *currentTiming) -{ - int fp_wid, fp_hgt, fp_vbs, fp_vbe; - u32 outputVal = 0; - - SET_DBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal, - (currentTiming->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1); - SET_DBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal, - (currentTiming->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1); - DBE_SETREG(vt_flags, outputVal); - - /* Turn on the flat panel */ - switch (flatpanel_id) { - case FLATPANEL_SGI_1600SW: - fp_wid = 1600; - fp_hgt = 1024; - fp_vbs = 0; - fp_vbe = 1600; - currentTiming->pll_m = 4; - currentTiming->pll_n = 1; - currentTiming->pll_p = 0; - break; - default: - fp_wid = fp_hgt = fp_vbs = fp_vbe = 0xfff; - } - - outputVal = 0; - SET_DBE_FIELD(FP_DE, FP_DE_ON, outputVal, fp_vbs); - SET_DBE_FIELD(FP_DE, FP_DE_OFF, outputVal, fp_vbe); - DBE_SETREG(fp_de, outputVal); - outputVal = 0; - SET_DBE_FIELD(FP_HDRV, FP_HDRV_OFF, outputVal, fp_wid); - DBE_SETREG(fp_hdrv, outputVal); - outputVal = 0; - SET_DBE_FIELD(FP_VDRV, FP_VDRV_ON, outputVal, 1); - SET_DBE_FIELD(FP_VDRV, FP_VDRV_OFF, outputVal, fp_hgt + 1); - DBE_SETREG(fp_vdrv, outputVal); -} - -/* - * Set the hardware according to 'par'. - */ -static int sgivwfb_set_par(struct fb_info *info) -{ - struct sgivw_par *par = info->par; - int i, j, htmp, temp; - u32 readVal, outputVal; - int wholeTilesX, maxPixelsPerTileX; - int frmWrite1, frmWrite2, frmWrite3b; - struct dbe_timing_info *currentTiming; /* Current Video Timing */ - int xpmax, ypmax; // Monitor resolution - int bytesPerPixel; // Bytes per pixel - - currentTiming = &dbeVTimings[par->timing_num]; - bytesPerPixel = bytes_per_pixel(info->var.bits_per_pixel); - xpmax = currentTiming->width; - ypmax = currentTiming->height; - - /* dbe_InitGraphicsBase(); */ - /* Turn on dotclock PLL */ - DBE_SETREG(ctrlstat, 0x20000000); - - dbe_TurnOffDma(par); - - /* dbe_CalculateScreenParams(); */ - maxPixelsPerTileX = 512 / bytesPerPixel; - wholeTilesX = xpmax / maxPixelsPerTileX; - if (wholeTilesX * maxPixelsPerTileX < xpmax) - wholeTilesX++; - - printk(KERN_DEBUG "sgivwfb: pixPerTile=%d wholeTilesX=%d\n", - maxPixelsPerTileX, wholeTilesX); - - /* dbe_InitGammaMap(); */ - udelay(10); - - for (i = 0; i < 256; i++) { - DBE_ISETREG(gmap, i, (i << 24) | (i << 16) | (i << 8)); - } - - /* dbe_TurnOn(); */ - DBE_GETREG(vt_xy, readVal); - if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1) { - DBE_SETREG(vt_xy, 0x00000000); - udelay(1); - } else - dbe_TurnOffDma(par); - - /* dbe_Initdbe(); */ - for (i = 0; i < 256; i++) { - for (j = 0; j < 100; j++) { - DBE_GETREG(cm_fifo, readVal); - if (readVal != 0x00000000) - break; - else - udelay(10); - } - - // DBE_ISETREG(cmap, i, 0x00000000); - DBE_ISETREG(cmap, i, (i << 8) | (i << 16) | (i << 24)); - } - - /* dbe_InitFramebuffer(); */ - frmWrite1 = 0; - SET_DBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, frmWrite1, - wholeTilesX); - SET_DBE_FIELD(FRM_SIZE_TILE, FRM_RHS, frmWrite1, 0); - - switch (bytesPerPixel) { - case 1: - SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, - DBE_FRM_DEPTH_8); - break; - case 2: - SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, - DBE_FRM_DEPTH_16); - break; - case 4: - SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, - DBE_FRM_DEPTH_32); - break; - } - - frmWrite2 = 0; - SET_DBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, frmWrite2, ypmax); - - // Tell dbe about the framebuffer location and type - // XXX What format is the FRM_TILE_PTR?? 64K aligned address? - frmWrite3b = 0; - SET_DBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, frmWrite3b, - sgivwfb_mem_phys >> 9); - SET_DBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, frmWrite3b, 1); - SET_DBE_FIELD(FRM_CONTROL, FRM_LINEAR, frmWrite3b, 1); - - /* Initialize DIDs */ - - outputVal = 0; - switch (bytesPerPixel) { - case 1: - SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_I8); - break; - case 2: - SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGBA5); - break; - case 4: - SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGB8); - break; - } - SET_DBE_FIELD(WID, BUF, outputVal, DBE_BMODE_BOTH); - - for (i = 0; i < 32; i++) { - DBE_ISETREG(mode_regs, i, outputVal); - } - - /* dbe_InitTiming(); */ - DBE_SETREG(vt_intr01, 0xffffffff); - DBE_SETREG(vt_intr23, 0xffffffff); - - DBE_GETREG(dotclock, readVal); - DBE_SETREG(dotclock, readVal & 0xffff); - - DBE_SETREG(vt_xymax, 0x00000000); - outputVal = 0; - SET_DBE_FIELD(VT_VSYNC, VT_VSYNC_ON, outputVal, - currentTiming->vsync_start); - SET_DBE_FIELD(VT_VSYNC, VT_VSYNC_OFF, outputVal, - currentTiming->vsync_end); - DBE_SETREG(vt_vsync, outputVal); - outputVal = 0; - SET_DBE_FIELD(VT_HSYNC, VT_HSYNC_ON, outputVal, - currentTiming->hsync_start); - SET_DBE_FIELD(VT_HSYNC, VT_HSYNC_OFF, outputVal, - currentTiming->hsync_end); - DBE_SETREG(vt_hsync, outputVal); - outputVal = 0; - SET_DBE_FIELD(VT_VBLANK, VT_VBLANK_ON, outputVal, - currentTiming->vblank_start); - SET_DBE_FIELD(VT_VBLANK, VT_VBLANK_OFF, outputVal, - currentTiming->vblank_end); - DBE_SETREG(vt_vblank, outputVal); - outputVal = 0; - SET_DBE_FIELD(VT_HBLANK, VT_HBLANK_ON, outputVal, - currentTiming->hblank_start); - SET_DBE_FIELD(VT_HBLANK, VT_HBLANK_OFF, outputVal, - currentTiming->hblank_end - 3); - DBE_SETREG(vt_hblank, outputVal); - outputVal = 0; - SET_DBE_FIELD(VT_VCMAP, VT_VCMAP_ON, outputVal, - currentTiming->vblank_start); - SET_DBE_FIELD(VT_VCMAP, VT_VCMAP_OFF, outputVal, - currentTiming->vblank_end); - DBE_SETREG(vt_vcmap, outputVal); - outputVal = 0; - SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_ON, outputVal, - currentTiming->hblank_start); - SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_OFF, outputVal, - currentTiming->hblank_end - 3); - DBE_SETREG(vt_hcmap, outputVal); - - if (flatpanel_id != -1) - sgivwfb_setup_flatpanel(par, currentTiming); - - outputVal = 0; - temp = currentTiming->vblank_start - currentTiming->vblank_end - 1; - if (temp > 0) - temp = -temp; - - SET_DBE_FIELD(DID_START_XY, DID_STARTY, outputVal, (u32) temp); - if (currentTiming->hblank_end >= 20) - SET_DBE_FIELD(DID_START_XY, DID_STARTX, outputVal, - currentTiming->hblank_end - 20); - else - SET_DBE_FIELD(DID_START_XY, DID_STARTX, outputVal, - currentTiming->htotal - (20 - - currentTiming-> - hblank_end)); - DBE_SETREG(did_start_xy, outputVal); - - outputVal = 0; - SET_DBE_FIELD(CRS_START_XY, CRS_STARTY, outputVal, - (u32) (temp + 1)); - if (currentTiming->hblank_end >= DBE_CRS_MAGIC) - SET_DBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal, - currentTiming->hblank_end - DBE_CRS_MAGIC); - else - SET_DBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal, - currentTiming->htotal - (DBE_CRS_MAGIC - - currentTiming-> - hblank_end)); - DBE_SETREG(crs_start_xy, outputVal); - - outputVal = 0; - SET_DBE_FIELD(VC_START_XY, VC_STARTY, outputVal, (u32) temp); - SET_DBE_FIELD(VC_START_XY, VC_STARTX, outputVal, - currentTiming->hblank_end - 4); - DBE_SETREG(vc_start_xy, outputVal); - - DBE_SETREG(frm_size_tile, frmWrite1); - DBE_SETREG(frm_size_pixel, frmWrite2); - - outputVal = 0; - SET_DBE_FIELD(DOTCLK, M, outputVal, currentTiming->pll_m - 1); - SET_DBE_FIELD(DOTCLK, N, outputVal, currentTiming->pll_n - 1); - SET_DBE_FIELD(DOTCLK, P, outputVal, currentTiming->pll_p); - SET_DBE_FIELD(DOTCLK, RUN, outputVal, 1); - DBE_SETREG(dotclock, outputVal); - - udelay(11 * 1000); - - DBE_SETREG(vt_vpixen, 0xffffff); - DBE_SETREG(vt_hpixen, 0xffffff); - - outputVal = 0; - SET_DBE_FIELD(VT_XYMAX, VT_MAXX, outputVal, currentTiming->htotal); - SET_DBE_FIELD(VT_XYMAX, VT_MAXY, outputVal, currentTiming->vtotal); - DBE_SETREG(vt_xymax, outputVal); - - outputVal = frmWrite1; - SET_DBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, outputVal, 1); - DBE_SETREG(frm_size_tile, outputVal); - DBE_SETREG(frm_size_tile, frmWrite1); - - outputVal = 0; - SET_DBE_FIELD(OVR_WIDTH_TILE, OVR_FIFO_RESET, outputVal, 1); - DBE_SETREG(ovr_width_tile, outputVal); - DBE_SETREG(ovr_width_tile, 0); - - DBE_SETREG(frm_control, frmWrite3b); - DBE_SETREG(did_control, 0); - - // Wait for dbe to take frame settings - for (i = 0; i < 100000; i++) { - DBE_GETREG(frm_inhwctrl, readVal); - if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) != - 0) - break; - else - udelay(1); - } - - if (i == 100000) - printk(KERN_INFO - "sgivwfb: timeout waiting for frame DMA enable.\n"); - - outputVal = 0; - htmp = currentTiming->hblank_end - 19; - if (htmp < 0) - htmp += currentTiming->htotal; /* allow blank to wrap around */ - SET_DBE_FIELD(VT_HPIXEN, VT_HPIXEN_ON, outputVal, htmp); - SET_DBE_FIELD(VT_HPIXEN, VT_HPIXEN_OFF, outputVal, - ((htmp + currentTiming->width - - 2) % currentTiming->htotal)); - DBE_SETREG(vt_hpixen, outputVal); - - outputVal = 0; - SET_DBE_FIELD(VT_VPIXEN, VT_VPIXEN_OFF, outputVal, - currentTiming->vblank_start); - SET_DBE_FIELD(VT_VPIXEN, VT_VPIXEN_ON, outputVal, - currentTiming->vblank_end); - DBE_SETREG(vt_vpixen, outputVal); - - // Turn off mouse cursor - par->regs->crs_ctl = 0; - - // XXX What's this section for?? - DBE_GETREG(ctrlstat, readVal); - readVal &= 0x02000000; - - if (readVal != 0) { - DBE_SETREG(ctrlstat, 0x30000000); - } - return 0; -} - -/* - * Set a single color register. The values supplied are already - * rounded down to the hardware's capabilities (according to the - * entries in the var structure). Return != 0 for invalid regno. - */ - -static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green, - u_int blue, u_int transp, - struct fb_info *info) -{ - struct sgivw_par *par = (struct sgivw_par *) info->par; - - if (regno > 255) - return 1; - red >>= 8; - green >>= 8; - blue >>= 8; - - /* wait for the color map FIFO to have a free entry */ - while (par->cmap_fifo == 0) - par->cmap_fifo = par->regs->cm_fifo; - - par->regs->cmap[regno] = (red << 24) | (green << 16) | (blue << 8); - par->cmap_fifo--; /* assume FIFO is filling up */ - return 0; -} - -static int sgivwfb_mmap(struct fb_info *info, - struct vm_area_struct *vma) -{ - int r; - - pgprot_val(vma->vm_page_prot) = - pgprot_val(vma->vm_page_prot) | _PAGE_PCD; - - r = vm_iomap_memory(vma, sgivwfb_mem_phys, sgivwfb_mem_size); - - printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n", - sgivwfb_mem_phys + (vma->vm_pgoff << PAGE_SHIFT), vma->vm_start); - - return r; -} - -int __init sgivwfb_setup(char *options) -{ - char *this_opt; - - if (!options || !*options) - return 0; - - while ((this_opt = strsep(&options, ",")) != NULL) { - if (!strncmp(this_opt, "monitor:", 8)) { - if (!strncmp(this_opt + 8, "crt", 3)) - flatpanel_id = -1; - else if (!strncmp(this_opt + 8, "1600sw", 6)) - flatpanel_id = FLATPANEL_SGI_1600SW; - } - } - return 0; -} - -/* - * Initialisation - */ -static int sgivwfb_probe(struct platform_device *dev) -{ - struct sgivw_par *par; - struct fb_info *info; - char *monitor; - - info = framebuffer_alloc(sizeof(struct sgivw_par) + sizeof(u32) * 16, &dev->dev); - if (!info) - return -ENOMEM; - par = info->par; - - if (!request_mem_region(DBE_REG_PHYS, DBE_REG_SIZE, "sgivwfb")) { - printk(KERN_ERR "sgivwfb: couldn't reserve mmio region\n"); - framebuffer_release(info); - return -EBUSY; - } - - par->regs = (struct asregs *) ioremap_nocache(DBE_REG_PHYS, DBE_REG_SIZE); - if (!par->regs) { - printk(KERN_ERR "sgivwfb: couldn't ioremap registers\n"); - goto fail_ioremap_regs; - } - - mtrr_add(sgivwfb_mem_phys, sgivwfb_mem_size, MTRR_TYPE_WRCOMB, 1); - - sgivwfb_fix.smem_start = sgivwfb_mem_phys; - sgivwfb_fix.smem_len = sgivwfb_mem_size; - sgivwfb_fix.ywrapstep = ywrap; - sgivwfb_fix.ypanstep = ypan; - - info->fix = sgivwfb_fix; - - switch (flatpanel_id) { - case FLATPANEL_SGI_1600SW: - info->var = sgivwfb_var1600sw; - monitor = "SGI 1600SW flatpanel"; - break; - default: - info->var = sgivwfb_var; - monitor = "CRT"; - } - - printk(KERN_INFO "sgivwfb: %s monitor selected\n", monitor); - - info->fbops = &sgivwfb_ops; - info->pseudo_palette = (void *) (par + 1); - info->flags = FBINFO_DEFAULT; - - info->screen_base = ioremap_nocache((unsigned long) sgivwfb_mem_phys, sgivwfb_mem_size); - if (!info->screen_base) { - printk(KERN_ERR "sgivwfb: couldn't ioremap screen_base\n"); - goto fail_ioremap_fbmem; - } - - if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) - goto fail_color_map; - - if (register_framebuffer(info) < 0) { - printk(KERN_ERR "sgivwfb: couldn't register framebuffer\n"); - goto fail_register_framebuffer; - } - - platform_set_drvdata(dev, info); - - fb_info(info, "SGI DBE frame buffer device, using %ldK of video memory at %#lx\n", - sgivwfb_mem_size >> 10, sgivwfb_mem_phys); - return 0; - -fail_register_framebuffer: - fb_dealloc_cmap(&info->cmap); -fail_color_map: - iounmap((char *) info->screen_base); -fail_ioremap_fbmem: - iounmap(par->regs); -fail_ioremap_regs: - release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE); - framebuffer_release(info); - return -ENXIO; -} - -static int sgivwfb_remove(struct platform_device *dev) -{ - struct fb_info *info = platform_get_drvdata(dev); - - if (info) { - struct sgivw_par *par = info->par; - - unregister_framebuffer(info); - dbe_TurnOffDma(par); - iounmap(par->regs); - iounmap(info->screen_base); - release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE); - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - } - return 0; -} - -static struct platform_driver sgivwfb_driver = { - .probe = sgivwfb_probe, - .remove = sgivwfb_remove, - .driver = { - .name = "sgivwfb", - }, -}; - -static struct platform_device *sgivwfb_device; - -int __init sgivwfb_init(void) -{ - int ret; - -#ifndef MODULE - char *option = NULL; - - if (fb_get_options("sgivwfb", &option)) - return -ENODEV; - sgivwfb_setup(option); -#endif - ret = platform_driver_register(&sgivwfb_driver); - if (!ret) { - sgivwfb_device = platform_device_alloc("sgivwfb", 0); - if (sgivwfb_device) { - ret = platform_device_add(sgivwfb_device); - } else - ret = -ENOMEM; - if (ret) { - platform_driver_unregister(&sgivwfb_driver); - platform_device_put(sgivwfb_device); - } - } - return ret; -} - -module_init(sgivwfb_init); - -#ifdef MODULE -MODULE_LICENSE("GPL"); - -static void __exit sgivwfb_exit(void) -{ - platform_device_unregister(sgivwfb_device); - platform_driver_unregister(&sgivwfb_driver); -} - -module_exit(sgivwfb_exit); - -#endif /* MODULE */ diff --git a/drivers/video/sis/init.c b/drivers/video/sis/init.c index 4f26bc28e60b..bd40f5ecd901 100644 --- a/drivers/video/sis/init.c +++ b/drivers/video/sis/init.c @@ -651,6 +651,7 @@ SiS_GetModeID_LCD(int VGAEngine, unsigned int VBFlags, int HDisplay, int VDispla switch(VDisplay) { case 720: ModeIndex = ModeIndex_1280x720[Depth]; + break; case 768: if(VGAEngine == SIS_300_VGA) { ModeIndex = ModeIndex_300_1280x768[Depth]; diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index 07c7df9ee77b..65ba9921506e 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c @@ -182,6 +182,8 @@ tgafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) if (var->xres_virtual != var->xres || var->yres_virtual != var->yres) return -EINVAL; + if (var->xres * var->yres * (var->bits_per_pixel >> 3) > info->fix.smem_len) + return -EINVAL; if (var->nonstd) return -EINVAL; if (1000000000 / var->pixclock > TGA_PLL_MAX_FREQ) @@ -190,8 +192,8 @@ tgafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) return -EINVAL; /* Some of the acceleration routines assume the line width is - a multiple of 64 bytes. */ - if (var->xres * (par->tga_type == TGA_TYPE_8PLANE ? 1 : 4) % 64) + a multiple of 8 bytes. */ + if (var->xres * (par->tga_type == TGA_TYPE_8PLANE ? 1 : 4) % 8) return -EINVAL; return 0; @@ -262,6 +264,7 @@ tgafb_set_par(struct fb_info *info) par->yres = info->var.yres; par->pll_freq = pll_freq = 1000000000 / info->var.pixclock; par->bits_per_pixel = info->var.bits_per_pixel; + info->fix.line_length = par->xres * (par->bits_per_pixel >> 3); tga_type = par->tga_type; @@ -1136,222 +1139,57 @@ copyarea_line_32bpp(struct fb_info *info, u32 dy, u32 sy, __raw_writel(TGA_MODE_SBM_24BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG); } -/* The general case of forward copy in 8bpp mode. */ +/* The (almost) general case of backward copy in 8bpp mode. */ static inline void -copyarea_foreward_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy, - u32 height, u32 width, u32 line_length) +copyarea_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy, + u32 height, u32 width, u32 line_length, + const struct fb_copyarea *area) { struct tga_par *par = (struct tga_par *) info->par; - unsigned long i, copied, left; - unsigned long dpos, spos, dalign, salign, yincr; - u32 smask_first, dmask_first, dmask_last; - int pixel_shift, need_prime, need_second; - unsigned long n64, n32, xincr_first; + unsigned i, yincr; + int depos, sepos, backward, last_step, step; + u32 mask_last; + unsigned n32; void __iomem *tga_regs; void __iomem *tga_fb; - yincr = line_length; - if (dy > sy) { - dy += height - 1; - sy += height - 1; - yincr = -yincr; - } - - /* Compute the offsets and alignments in the frame buffer. - More than anything else, these control how we do copies. */ - dpos = dy * line_length + dx; - spos = sy * line_length + sx; - dalign = dpos & 7; - salign = spos & 7; - dpos &= -8; - spos &= -8; - - /* Compute the value for the PIXELSHIFT register. This controls - both non-co-aligned source and destination and copy direction. */ - if (dalign >= salign) - pixel_shift = dalign - salign; - else - pixel_shift = 8 - (salign - dalign); - - /* Figure out if we need an additional priming step for the - residue register. */ - need_prime = (salign > dalign); - if (need_prime) - dpos -= 8; - - /* Begin by copying the leading unaligned destination. Copy enough - to make the next destination address 32-byte aligned. */ - copied = 32 - (dalign + (dpos & 31)); - if (copied == 32) - copied = 0; - xincr_first = (copied + 7) & -8; - smask_first = dmask_first = (1ul << copied) - 1; - smask_first <<= salign; - dmask_first <<= dalign + need_prime*8; - if (need_prime && copied > 24) - copied -= 8; - left = width - copied; - - /* Care for small copies. */ - if (copied > width) { - u32 t; - t = (1ul << width) - 1; - t <<= dalign + need_prime*8; - dmask_first &= t; - left = 0; - } - - /* Attempt to use 64-byte copies. This is only possible if the - source and destination are co-aligned at 64 bytes. */ - n64 = need_second = 0; - if ((dpos & 63) == (spos & 63) - && (height == 1 || line_length % 64 == 0)) { - /* We may need a 32-byte copy to ensure 64 byte alignment. */ - need_second = (dpos + xincr_first) & 63; - if ((need_second & 32) != need_second) - printk(KERN_ERR "tgafb: need_second wrong\n"); - if (left >= need_second + 64) { - left -= need_second; - n64 = left / 64; - left %= 64; - } else - need_second = 0; - } - - /* Copy trailing full 32-byte sections. This will be the main - loop if the 64 byte loop can't be used. */ - n32 = left / 32; - left %= 32; - - /* Copy the trailing unaligned destination. */ - dmask_last = (1ul << left) - 1; - - tga_regs = par->tga_regs_base; - tga_fb = par->tga_fb_base; - - /* Set up the MODE and PIXELSHIFT registers. */ - __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_COPY, tga_regs+TGA_MODE_REG); - __raw_writel(pixel_shift, tga_regs+TGA_PIXELSHIFT_REG); - wmb(); - - for (i = 0; i < height; ++i) { - unsigned long j; - void __iomem *sfb; - void __iomem *dfb; - - sfb = tga_fb + spos; - dfb = tga_fb + dpos; - if (dmask_first) { - __raw_writel(smask_first, sfb); - wmb(); - __raw_writel(dmask_first, dfb); - wmb(); - sfb += xincr_first; - dfb += xincr_first; - } - - if (need_second) { - __raw_writel(0xffffffff, sfb); - wmb(); - __raw_writel(0xffffffff, dfb); - wmb(); - sfb += 32; - dfb += 32; - } - - if (n64 && (((unsigned long)sfb | (unsigned long)dfb) & 63)) - printk(KERN_ERR - "tgafb: misaligned copy64 (s:%p, d:%p)\n", - sfb, dfb); - - for (j = 0; j < n64; ++j) { - __raw_writel(sfb - tga_fb, tga_regs+TGA_COPY64_SRC); - wmb(); - __raw_writel(dfb - tga_fb, tga_regs+TGA_COPY64_DST); - wmb(); - sfb += 64; - dfb += 64; - } - - for (j = 0; j < n32; ++j) { - __raw_writel(0xffffffff, sfb); - wmb(); - __raw_writel(0xffffffff, dfb); - wmb(); - sfb += 32; - dfb += 32; - } - - if (dmask_last) { - __raw_writel(0xffffffff, sfb); - wmb(); - __raw_writel(dmask_last, dfb); - wmb(); - } - - spos += yincr; - dpos += yincr; + /* Do acceleration only if we are aligned on 8 pixels */ + if ((dx | sx | width) & 7) { + cfb_copyarea(info, area); + return; } - /* Reset the MODE register to normal. */ - __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG); -} - -/* The (almost) general case of backward copy in 8bpp mode. */ -static inline void -copyarea_backward_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy, - u32 height, u32 width, u32 line_length, - const struct fb_copyarea *area) -{ - struct tga_par *par = (struct tga_par *) info->par; - unsigned long i, left, yincr; - unsigned long depos, sepos, dealign, sealign; - u32 mask_first, mask_last; - unsigned long n32; - void __iomem *tga_regs; - void __iomem *tga_fb; - yincr = line_length; if (dy > sy) { dy += height - 1; sy += height - 1; yincr = -yincr; } + backward = dy == sy && dx > sx && dx < sx + width; /* Compute the offsets and alignments in the frame buffer. More than anything else, these control how we do copies. */ - depos = dy * line_length + dx + width; - sepos = sy * line_length + sx + width; - dealign = depos & 7; - sealign = sepos & 7; - - /* ??? The documentation appears to be incorrect (or very - misleading) wrt how pixel shifting works in backward copy - mode, i.e. when PIXELSHIFT is negative. I give up for now. - Do handle the common case of co-aligned backward copies, - but frob everything else back on generic code. */ - if (dealign != sealign) { - cfb_copyarea(info, area); - return; - } - - /* We begin the copy with the trailing pixels of the - unaligned destination. */ - mask_first = (1ul << dealign) - 1; - left = width - dealign; - - /* Care for small copies. */ - if (dealign > width) { - mask_first ^= (1ul << (dealign - width)) - 1; - left = 0; - } + depos = dy * line_length + dx; + sepos = sy * line_length + sx; + if (backward) + depos += width, sepos += width; /* Next copy full words at a time. */ - n32 = left / 32; - left %= 32; + n32 = width / 32; + last_step = width % 32; /* Finally copy the unaligned head of the span. */ - mask_last = -1 << (32 - left); + mask_last = (1ul << last_step) - 1; + + if (!backward) { + step = 32; + last_step = 32; + } else { + step = -32; + last_step = -last_step; + sepos -= 32; + depos -= 32; + } tga_regs = par->tga_regs_base; tga_fb = par->tga_fb_base; @@ -1368,25 +1206,33 @@ copyarea_backward_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy, sfb = tga_fb + sepos; dfb = tga_fb + depos; - if (mask_first) { - __raw_writel(mask_first, sfb); - wmb(); - __raw_writel(mask_first, dfb); - wmb(); - } - for (j = 0; j < n32; ++j) { - sfb -= 32; - dfb -= 32; + for (j = 0; j < n32; j++) { + if (j < 2 && j + 1 < n32 && !backward && + !(((unsigned long)sfb | (unsigned long)dfb) & 63)) { + do { + __raw_writel(sfb - tga_fb, tga_regs+TGA_COPY64_SRC); + wmb(); + __raw_writel(dfb - tga_fb, tga_regs+TGA_COPY64_DST); + wmb(); + sfb += 64; + dfb += 64; + j += 2; + } while (j + 1 < n32); + j--; + continue; + } __raw_writel(0xffffffff, sfb); wmb(); __raw_writel(0xffffffff, dfb); wmb(); + sfb += step; + dfb += step; } if (mask_last) { - sfb -= 32; - dfb -= 32; + sfb += last_step - step; + dfb += last_step - step; __raw_writel(mask_last, sfb); wmb(); __raw_writel(mask_last, dfb); @@ -1434,7 +1280,7 @@ tgafb_copyarea(struct fb_info *info, const struct fb_copyarea *area) bpp = info->var.bits_per_pixel; /* Detect copies of the entire line. */ - if (width * (bpp >> 3) == line_length) { + if (!(line_length & 63) && width * (bpp >> 3) == line_length) { if (bpp == 8) copyarea_line_8bpp(info, dy, sy, height, width); else @@ -1447,14 +1293,9 @@ tgafb_copyarea(struct fb_info *info, const struct fb_copyarea *area) else if (bpp == 32) cfb_copyarea(info, area); - /* Detect overlapping source and destination that requires - a backward copy. */ - else if (dy == sy && dx > sx && dx < sx + width) - copyarea_backward_8bpp(info, dx, dy, sx, sy, height, - width, line_length, area); else - copyarea_foreward_8bpp(info, dx, dy, sx, sy, height, - width, line_length); + copyarea_8bpp(info, dx, dy, sx, sy, height, + width, line_length, area); } @@ -1470,6 +1311,7 @@ tgafb_init_fix(struct fb_info *info) int tga_bus_tc = TGA_BUS_TC(par->dev); u8 tga_type = par->tga_type; const char *tga_type_name = NULL; + unsigned memory_size; switch (tga_type) { case TGA_TYPE_8PLANE: @@ -1477,22 +1319,27 @@ tgafb_init_fix(struct fb_info *info) tga_type_name = "Digital ZLXp-E1"; if (tga_bus_tc) tga_type_name = "Digital ZLX-E1"; + memory_size = 2097152; break; case TGA_TYPE_24PLANE: if (tga_bus_pci) tga_type_name = "Digital ZLXp-E2"; if (tga_bus_tc) tga_type_name = "Digital ZLX-E2"; + memory_size = 8388608; break; case TGA_TYPE_24PLUSZ: if (tga_bus_pci) tga_type_name = "Digital ZLXp-E3"; if (tga_bus_tc) tga_type_name = "Digital ZLX-E3"; + memory_size = 16777216; break; } - if (!tga_type_name) + if (!tga_type_name) { tga_type_name = "Unknown"; + memory_size = 16777216; + } strlcpy(info->fix.id, tga_type_name, sizeof(info->fix.id)); @@ -1502,9 +1349,8 @@ tgafb_init_fix(struct fb_info *info) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR); - info->fix.line_length = par->xres * (par->bits_per_pixel >> 3); info->fix.smem_start = (size_t) par->tga_fb_base; - info->fix.smem_len = info->fix.line_length * par->yres; + info->fix.smem_len = memory_size; info->fix.mmio_start = (size_t) par->tga_regs_base; info->fix.mmio_len = 512; @@ -1628,6 +1474,9 @@ static int tgafb_register(struct device *dev) modedb_tga = &modedb_tc; modedbsize_tga = 1; } + + tgafb_init_fix(info); + ret = fb_find_mode(&info->var, info, mode_option ? mode_option : mode_option_tga, modedb_tga, modedbsize_tga, NULL, @@ -1645,7 +1494,6 @@ static int tgafb_register(struct device *dev) } tgafb_set_par(info); - tgafb_init_fix(info); if (register_framebuffer(info) < 0) { printk(KERN_ERR "tgafb: Could not register framebuffer\n"); diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index 256fba7f4641..509d452e8f91 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -190,7 +190,7 @@ static int uvesafb_exec(struct uvesafb_ktask *task) uvfb_tasks[seq] = task; mutex_unlock(&uvfb_lock); - err = cn_netlink_send(m, 0, GFP_KERNEL); + err = cn_netlink_send(m, 0, 0, GFP_KERNEL); if (err == -ESRCH) { /* * Try to start the userspace helper if sending @@ -204,7 +204,7 @@ static int uvesafb_exec(struct uvesafb_ktask *task) "helper is installed and executable\n"); } else { v86d_started = 1; - err = cn_netlink_send(m, 0, gfp_any()); + err = cn_netlink_send(m, 0, 0, gfp_any()); if (err == -ENOBUFS) err = 0; } @@ -1474,12 +1474,7 @@ static void uvesafb_init_info(struct fb_info *info, struct vbe_mode_ib *mode) * used video mode, i.e. the minimum amount of * memory we need. */ - if (mode != NULL) { - size_vmode = info->var.yres * mode->bytes_per_scan_line; - } else { - size_vmode = info->var.yres * info->var.xres * - ((info->var.bits_per_pixel + 7) >> 3); - } + size_vmode = info->var.yres * mode->bytes_per_scan_line; /* * size_total -- all video memory we have. Used for mtrr @@ -1812,11 +1807,9 @@ static int uvesafb_remove(struct platform_device *dev) fb_destroy_modedb(info->monspecs.modedb); fb_dealloc_cmap(&info->cmap); - if (par) { - kfree(par->vbe_modes); - kfree(par->vbe_state_orig); - kfree(par->vbe_state_saved); - } + kfree(par->vbe_modes); + kfree(par->vbe_state_orig); + kfree(par->vbe_state_saved); framebuffer_release(info); } diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index 1c7da3b098d6..6170e7f58640 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -179,7 +179,6 @@ static void vesafb_destroy(struct fb_info *info) if (info->screen_base) iounmap(info->screen_base); release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); - framebuffer_release(info); } static struct fb_ops vesafb_ops = { @@ -297,6 +296,7 @@ static int vesafb_probe(struct platform_device *dev) release_mem_region(vesafb_fix.smem_start, size_total); return -ENOMEM; } + platform_set_drvdata(dev, info); info->pseudo_palette = info->par; info->par = NULL; @@ -499,12 +499,23 @@ err: return err; } +static int vesafb_remove(struct platform_device *pdev) +{ + struct fb_info *info = platform_get_drvdata(pdev); + + unregister_framebuffer(info); + framebuffer_release(info); + + return 0; +} + static struct platform_driver vesafb_driver = { .driver = { .name = "vesa-framebuffer", .owner = THIS_MODULE, }, .probe = vesafb_probe, + .remove = vesafb_remove, }; module_platform_driver(vesafb_driver); diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 6ff1a91e9dfd..553cff2f3f4c 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -33,7 +33,6 @@ #include <linux/of_platform.h> #include <linux/of_address.h> #include <linux/io.h> -#include <linux/xilinxfb.h> #include <linux/slab.h> #ifdef CONFIG_PPC_DCR @@ -84,6 +83,20 @@ #define PALETTE_ENTRIES_NO 16 /* passed to fb_alloc_cmap() */ +/* ML300/403 reference design framebuffer driver platform data struct */ +struct xilinxfb_platform_data { + u32 rotate_screen; /* Flag to rotate display 180 degrees */ + u32 screen_height_mm; /* Physical dimensions of screen in mm */ + u32 screen_width_mm; + u32 xres, yres; /* resolution of screen in pixels */ + u32 xvirt, yvirt; /* resolution of memory buffer */ + + /* Physical address of framebuffer memory; If non-zero, driver + * will use provided memory address instead of allocating one from + * the consistent pool. */ + u32 fb_phys; +}; + /* * Default xilinxfb configuration */ |