diff options
Diffstat (limited to 'drivers/video')
49 files changed, 2425 insertions, 341 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 8bf495ffb..e0606c01e 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -22,9 +22,7 @@ source "drivers/gpu/vga/Kconfig" source "drivers/gpu/host1x/Kconfig" source "drivers/gpu/ipu-v3/Kconfig" -menu "Direct Rendering Manager" source "drivers/gpu/drm/Kconfig" -endmenu menu "Frame buffer Devices" source "drivers/video/fbdev/Kconfig" diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 0505b796d..5ffa4b4e2 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -299,6 +299,13 @@ config BACKLIGHT_TOSA If you have an Sharp SL-6000 Zaurus say Y to enable a driver for its backlight +config BACKLIGHT_PM8941_WLED + tristate "Qualcomm PM8941 WLED Driver" + select REGMAP + help + If you have the Qualcomm PM8941, say Y to enable a driver for the + WLED block. + config BACKLIGHT_SAHARA tristate "Tabletkiosk Sahara Touch-iT Backlight Driver" depends on X86 diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index d67073f9d..16ec534cf 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o +obj-$(CONFIG_BACKLIGHT_PM8941_WLED) += pm8941-wled.o obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c index 88116b493..f88df9ec0 100644 --- a/drivers/video/backlight/lp855x_bl.c +++ b/drivers/video/backlight/lp855x_bl.c @@ -73,6 +73,7 @@ struct lp855x { struct device *dev; struct lp855x_platform_data *pdata; struct pwm_device *pwm; + struct regulator *supply; /* regulator for VDD input */ }; static int lp855x_write_byte(struct lp855x *lp, u8 reg, u8 data) @@ -378,13 +379,6 @@ static int lp855x_parse_dt(struct lp855x *lp) pdata->rom_data = &rom[0]; } - pdata->supply = devm_regulator_get(dev, "power"); - if (IS_ERR(pdata->supply)) { - if (PTR_ERR(pdata->supply) == -EPROBE_DEFER) - return -EPROBE_DEFER; - pdata->supply = NULL; - } - lp->pdata = pdata; return 0; @@ -425,8 +419,15 @@ static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id) else lp->mode = REGISTER_BASED; - if (lp->pdata->supply) { - ret = regulator_enable(lp->pdata->supply); + lp->supply = devm_regulator_get(lp->dev, "power"); + if (IS_ERR(lp->supply)) { + if (PTR_ERR(lp->supply) == -EPROBE_DEFER) + return -EPROBE_DEFER; + lp->supply = NULL; + } + + if (lp->supply) { + ret = regulator_enable(lp->supply); if (ret < 0) { dev_err(&cl->dev, "failed to enable supply: %d\n", ret); return ret; @@ -464,8 +465,8 @@ static int lp855x_remove(struct i2c_client *cl) lp->bl->props.brightness = 0; backlight_update_status(lp->bl); - if (lp->pdata->supply) - regulator_disable(lp->pdata->supply); + if (lp->supply) + regulator_disable(lp->supply); sysfs_remove_group(&lp->dev->kobj, &lp855x_attr_group); return 0; diff --git a/drivers/video/backlight/lp8788_bl.c b/drivers/video/backlight/lp8788_bl.c index e418d5b1a..5d583d7a5 100644 --- a/drivers/video/backlight/lp8788_bl.c +++ b/drivers/video/backlight/lp8788_bl.c @@ -221,8 +221,7 @@ static void lp8788_backlight_unregister(struct lp8788_bl *bl) { struct backlight_device *bl_dev = bl->bl_dev; - if (bl_dev) - backlight_device_unregister(bl_dev); + backlight_device_unregister(bl_dev); } static ssize_t lp8788_get_bl_ctl_mode(struct device *dev, diff --git a/drivers/video/backlight/pm8941-wled.c b/drivers/video/backlight/pm8941-wled.c new file mode 100644 index 000000000..c704c3236 --- /dev/null +++ b/drivers/video/backlight/pm8941-wled.c @@ -0,0 +1,427 @@ +/* Copyright (c) 2015, Sony Mobile Communications, AB. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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/kernel.h> +#include <linux/backlight.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/regmap.h> + +#define PM8941_WLED_REG_VAL_BASE 0x40 +#define PM8941_WLED_REG_VAL_MAX 0xFFF + +#define PM8941_WLED_REG_MOD_EN 0x46 +#define PM8941_WLED_REG_MOD_EN_BIT BIT(7) +#define PM8941_WLED_REG_MOD_EN_MASK BIT(7) + +#define PM8941_WLED_REG_SYNC 0x47 +#define PM8941_WLED_REG_SYNC_MASK 0x07 +#define PM8941_WLED_REG_SYNC_LED1 BIT(0) +#define PM8941_WLED_REG_SYNC_LED2 BIT(1) +#define PM8941_WLED_REG_SYNC_LED3 BIT(2) +#define PM8941_WLED_REG_SYNC_ALL 0x07 +#define PM8941_WLED_REG_SYNC_CLEAR 0x00 + +#define PM8941_WLED_REG_FREQ 0x4c +#define PM8941_WLED_REG_FREQ_MASK 0x0f + +#define PM8941_WLED_REG_OVP 0x4d +#define PM8941_WLED_REG_OVP_MASK 0x03 + +#define PM8941_WLED_REG_BOOST 0x4e +#define PM8941_WLED_REG_BOOST_MASK 0x07 + +#define PM8941_WLED_REG_SINK 0x4f +#define PM8941_WLED_REG_SINK_MASK 0xe0 +#define PM8941_WLED_REG_SINK_SHFT 0x05 + +/* Per-'string' registers below */ +#define PM8941_WLED_REG_STR_OFFSET 0x10 + +#define PM8941_WLED_REG_STR_MOD_EN_BASE 0x60 +#define PM8941_WLED_REG_STR_MOD_MASK BIT(7) +#define PM8941_WLED_REG_STR_MOD_EN BIT(7) + +#define PM8941_WLED_REG_STR_SCALE_BASE 0x62 +#define PM8941_WLED_REG_STR_SCALE_MASK 0x1f + +#define PM8941_WLED_REG_STR_MOD_SRC_BASE 0x63 +#define PM8941_WLED_REG_STR_MOD_SRC_MASK 0x01 +#define PM8941_WLED_REG_STR_MOD_SRC_INT 0x00 +#define PM8941_WLED_REG_STR_MOD_SRC_EXT 0x01 + +#define PM8941_WLED_REG_STR_CABC_BASE 0x66 +#define PM8941_WLED_REG_STR_CABC_MASK BIT(7) +#define PM8941_WLED_REG_STR_CABC_EN BIT(7) + +struct pm8941_wled_config { + u32 i_boost_limit; + u32 ovp; + u32 switch_freq; + u32 num_strings; + u32 i_limit; + bool cs_out_en; + bool ext_gen; + bool cabc_en; +}; + +struct pm8941_wled { + const char *name; + struct regmap *regmap; + u16 addr; + + struct pm8941_wled_config cfg; +}; + +static int pm8941_wled_update_status(struct backlight_device *bl) +{ + struct pm8941_wled *wled = bl_get_data(bl); + u16 val = bl->props.brightness; + u8 ctrl = 0; + int rc; + int i; + + if (bl->props.power != FB_BLANK_UNBLANK || + bl->props.fb_blank != FB_BLANK_UNBLANK || + bl->props.state & BL_CORE_FBBLANK) + val = 0; + + if (val != 0) + ctrl = PM8941_WLED_REG_MOD_EN_BIT; + + rc = regmap_update_bits(wled->regmap, + wled->addr + PM8941_WLED_REG_MOD_EN, + PM8941_WLED_REG_MOD_EN_MASK, ctrl); + if (rc) + return rc; + + for (i = 0; i < wled->cfg.num_strings; ++i) { + u8 v[2] = { val & 0xff, (val >> 8) & 0xf }; + + rc = regmap_bulk_write(wled->regmap, + wled->addr + PM8941_WLED_REG_VAL_BASE + 2 * i, + v, 2); + if (rc) + return rc; + } + + rc = regmap_update_bits(wled->regmap, + wled->addr + PM8941_WLED_REG_SYNC, + PM8941_WLED_REG_SYNC_MASK, PM8941_WLED_REG_SYNC_ALL); + if (rc) + return rc; + + rc = regmap_update_bits(wled->regmap, + wled->addr + PM8941_WLED_REG_SYNC, + PM8941_WLED_REG_SYNC_MASK, PM8941_WLED_REG_SYNC_CLEAR); + return rc; +} + +static int pm8941_wled_setup(struct pm8941_wled *wled) +{ + int rc; + int i; + + rc = regmap_update_bits(wled->regmap, + wled->addr + PM8941_WLED_REG_OVP, + PM8941_WLED_REG_OVP_MASK, wled->cfg.ovp); + if (rc) + return rc; + + rc = regmap_update_bits(wled->regmap, + wled->addr + PM8941_WLED_REG_BOOST, + PM8941_WLED_REG_BOOST_MASK, wled->cfg.i_boost_limit); + if (rc) + return rc; + + rc = regmap_update_bits(wled->regmap, + wled->addr + PM8941_WLED_REG_FREQ, + PM8941_WLED_REG_FREQ_MASK, wled->cfg.switch_freq); + if (rc) + return rc; + + if (wled->cfg.cs_out_en) { + u8 all = (BIT(wled->cfg.num_strings) - 1) + << PM8941_WLED_REG_SINK_SHFT; + + rc = regmap_update_bits(wled->regmap, + wled->addr + PM8941_WLED_REG_SINK, + PM8941_WLED_REG_SINK_MASK, all); + if (rc) + return rc; + } + + for (i = 0; i < wled->cfg.num_strings; ++i) { + u16 addr = wled->addr + PM8941_WLED_REG_STR_OFFSET * i; + + rc = regmap_update_bits(wled->regmap, + addr + PM8941_WLED_REG_STR_MOD_EN_BASE, + PM8941_WLED_REG_STR_MOD_MASK, + PM8941_WLED_REG_STR_MOD_EN); + if (rc) + return rc; + + if (wled->cfg.ext_gen) { + rc = regmap_update_bits(wled->regmap, + addr + PM8941_WLED_REG_STR_MOD_SRC_BASE, + PM8941_WLED_REG_STR_MOD_SRC_MASK, + PM8941_WLED_REG_STR_MOD_SRC_EXT); + if (rc) + return rc; + } + + rc = regmap_update_bits(wled->regmap, + addr + PM8941_WLED_REG_STR_SCALE_BASE, + PM8941_WLED_REG_STR_SCALE_MASK, + wled->cfg.i_limit); + if (rc) + return rc; + + rc = regmap_update_bits(wled->regmap, + addr + PM8941_WLED_REG_STR_CABC_BASE, + PM8941_WLED_REG_STR_CABC_MASK, + wled->cfg.cabc_en ? + PM8941_WLED_REG_STR_CABC_EN : 0); + if (rc) + return rc; + } + + return 0; +} + +static const struct pm8941_wled_config pm8941_wled_config_defaults = { + .i_boost_limit = 3, + .i_limit = 20, + .ovp = 2, + .switch_freq = 5, + .num_strings = 0, + .cs_out_en = false, + .ext_gen = false, + .cabc_en = false, +}; + +struct pm8941_wled_var_cfg { + const u32 *values; + u32 (*fn)(u32); + int size; +}; + +static const u32 pm8941_wled_i_boost_limit_values[] = { + 105, 385, 525, 805, 980, 1260, 1400, 1680, +}; + +static const struct pm8941_wled_var_cfg pm8941_wled_i_boost_limit_cfg = { + .values = pm8941_wled_i_boost_limit_values, + .size = ARRAY_SIZE(pm8941_wled_i_boost_limit_values), +}; + +static const u32 pm8941_wled_ovp_values[] = { + 35, 32, 29, 27, +}; + +static const struct pm8941_wled_var_cfg pm8941_wled_ovp_cfg = { + .values = pm8941_wled_ovp_values, + .size = ARRAY_SIZE(pm8941_wled_ovp_values), +}; + +static u32 pm8941_wled_num_strings_values_fn(u32 idx) +{ + return idx + 1; +} + +static const struct pm8941_wled_var_cfg pm8941_wled_num_strings_cfg = { + .fn = pm8941_wled_num_strings_values_fn, + .size = 3, +}; + +static u32 pm8941_wled_switch_freq_values_fn(u32 idx) +{ + return 19200 / (2 * (1 + idx)); +} + +static const struct pm8941_wled_var_cfg pm8941_wled_switch_freq_cfg = { + .fn = pm8941_wled_switch_freq_values_fn, + .size = 16, +}; + +static const struct pm8941_wled_var_cfg pm8941_wled_i_limit_cfg = { + .size = 26, +}; + +static u32 pm8941_wled_values(const struct pm8941_wled_var_cfg *cfg, u32 idx) +{ + if (idx >= cfg->size) + return UINT_MAX; + if (cfg->fn) + return cfg->fn(idx); + if (cfg->values) + return cfg->values[idx]; + return idx; +} + +static int pm8941_wled_configure(struct pm8941_wled *wled, struct device *dev) +{ + struct pm8941_wled_config *cfg = &wled->cfg; + u32 val; + int rc; + u32 c; + int i; + int j; + + const struct { + const char *name; + u32 *val_ptr; + const struct pm8941_wled_var_cfg *cfg; + } u32_opts[] = { + { + "qcom,current-boost-limit", + &cfg->i_boost_limit, + .cfg = &pm8941_wled_i_boost_limit_cfg, + }, + { + "qcom,current-limit", + &cfg->i_limit, + .cfg = &pm8941_wled_i_limit_cfg, + }, + { + "qcom,ovp", + &cfg->ovp, + .cfg = &pm8941_wled_ovp_cfg, + }, + { + "qcom,switching-freq", + &cfg->switch_freq, + .cfg = &pm8941_wled_switch_freq_cfg, + }, + { + "qcom,num-strings", + &cfg->num_strings, + .cfg = &pm8941_wled_num_strings_cfg, + }, + }; + const struct { + const char *name; + bool *val_ptr; + } bool_opts[] = { + { "qcom,cs-out", &cfg->cs_out_en, }, + { "qcom,ext-gen", &cfg->ext_gen, }, + { "qcom,cabc", &cfg->cabc_en, }, + }; + + rc = of_property_read_u32(dev->of_node, "reg", &val); + if (rc || val > 0xffff) { + dev_err(dev, "invalid IO resources\n"); + return rc ? rc : -EINVAL; + } + wled->addr = val; + + rc = of_property_read_string(dev->of_node, "label", &wled->name); + if (rc) + wled->name = dev->of_node->name; + + *cfg = pm8941_wled_config_defaults; + for (i = 0; i < ARRAY_SIZE(u32_opts); ++i) { + rc = of_property_read_u32(dev->of_node, u32_opts[i].name, &val); + if (rc == -EINVAL) { + continue; + } else if (rc) { + dev_err(dev, "error reading '%s'\n", u32_opts[i].name); + return rc; + } + + c = UINT_MAX; + for (j = 0; c != val; j++) { + c = pm8941_wled_values(u32_opts[i].cfg, j); + if (c == UINT_MAX) { + dev_err(dev, "invalid value for '%s'\n", + u32_opts[i].name); + return -EINVAL; + } + } + + dev_dbg(dev, "'%s' = %u\n", u32_opts[i].name, c); + *u32_opts[i].val_ptr = j; + } + + for (i = 0; i < ARRAY_SIZE(bool_opts); ++i) { + if (of_property_read_bool(dev->of_node, bool_opts[i].name)) + *bool_opts[i].val_ptr = true; + } + + cfg->num_strings = cfg->num_strings + 1; + + return 0; +} + +static const struct backlight_ops pm8941_wled_ops = { + .update_status = pm8941_wled_update_status, +}; + +static int pm8941_wled_probe(struct platform_device *pdev) +{ + struct backlight_properties props; + struct backlight_device *bl; + struct pm8941_wled *wled; + struct regmap *regmap; + int rc; + + regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!regmap) { + dev_err(&pdev->dev, "Unable to get regmap\n"); + return -EINVAL; + } + + wled = devm_kzalloc(&pdev->dev, sizeof(*wled), GFP_KERNEL); + if (!wled) + return -ENOMEM; + + wled->regmap = regmap; + + rc = pm8941_wled_configure(wled, &pdev->dev); + if (rc) + return rc; + + rc = pm8941_wled_setup(wled); + if (rc) + return rc; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; + props.max_brightness = PM8941_WLED_REG_VAL_MAX; + bl = devm_backlight_device_register(&pdev->dev, wled->name, + &pdev->dev, wled, + &pm8941_wled_ops, &props); + if (IS_ERR(bl)) + return PTR_ERR(bl); + + return 0; +}; + +static const struct of_device_id pm8941_wled_match_table[] = { + { .compatible = "qcom,pm8941-wled" }, + {} +}; +MODULE_DEVICE_TABLE(of, pm8941_wled_match_table); + +static struct platform_driver pm8941_wled_driver = { + .probe = pm8941_wled_probe, + .driver = { + .name = "pm8941-wled", + .of_match_table = pm8941_wled_match_table, + }, +}; + +module_platform_driver(pm8941_wled_driver); + +MODULE_DESCRIPTION("pm8941 wled driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/video/backlight/sky81452-backlight.c b/drivers/video/backlight/sky81452-backlight.c index 052fa1bac..d414c7a3a 100644 --- a/drivers/video/backlight/sky81452-backlight.c +++ b/drivers/video/backlight/sky81452-backlight.c @@ -65,7 +65,7 @@ static int sky81452_bl_update_status(struct backlight_device *bd) if (brightness > 0) { ret = regmap_write(regmap, SKY81452_REG0, brightness - 1); - if (IS_ERR_VALUE(ret)) + if (ret < 0) return ret; return regmap_update_bits(regmap, SKY81452_REG1, SKY81452_EN, @@ -87,12 +87,12 @@ static ssize_t sky81452_bl_store_enable(struct device *dev, int ret; ret = kstrtoul(buf, 16, &value); - if (IS_ERR_VALUE(ret)) + if (ret < 0) return ret; ret = regmap_update_bits(regmap, SKY81452_REG1, SKY81452_EN, value << CTZ(SKY81452_EN)); - if (IS_ERR_VALUE(ret)) + if (ret < 0) return ret; return count; @@ -108,7 +108,7 @@ static ssize_t sky81452_bl_show_open_short(struct device *dev, reg = !strcmp(attr->attr.name, "open") ? SKY81452_REG5 : SKY81452_REG4; ret = regmap_read(regmap, reg, &value); - if (IS_ERR_VALUE(ret)) + if (ret < 0) return ret; if (value & SKY81452_SHRT) { @@ -136,7 +136,7 @@ static ssize_t sky81452_bl_show_fault(struct device *dev, int ret; ret = regmap_read(regmap, SKY81452_REG4, &value); - if (IS_ERR_VALUE(ret)) + if (ret < 0) return ret; *buf = 0; @@ -196,7 +196,7 @@ static struct sky81452_bl_platform_data *sky81452_bl_parse_dt( pdata->gpio_enable = of_get_gpio(np, 0); ret = of_property_count_u32_elems(np, "led-sources"); - if (IS_ERR_VALUE(ret)) { + if (ret < 0) { pdata->enable = SKY81452_EN >> CTZ(SKY81452_EN); } else { num_entry = ret; @@ -205,7 +205,7 @@ static struct sky81452_bl_platform_data *sky81452_bl_parse_dt( ret = of_property_read_u32_array(np, "led-sources", sources, num_entry); - if (IS_ERR_VALUE(ret)) { + if (ret < 0) { dev_err(dev, "led-sources node is invalid.\n"); return ERR_PTR(-EINVAL); } @@ -218,12 +218,12 @@ static struct sky81452_bl_platform_data *sky81452_bl_parse_dt( ret = of_property_read_u32(np, "skyworks,short-detection-threshold-volt", &pdata->short_detection_threshold); - if (IS_ERR_VALUE(ret)) + if (ret < 0) pdata->short_detection_threshold = 7; ret = of_property_read_u32(np, "skyworks,current-limit-mA", &pdata->boost_current_limit); - if (IS_ERR_VALUE(ret)) + if (ret < 0) pdata->boost_current_limit = 2750; of_node_put(np); @@ -278,14 +278,14 @@ static int sky81452_bl_probe(struct platform_device *pdev) if (gpio_is_valid(pdata->gpio_enable)) { ret = devm_gpio_request_one(dev, pdata->gpio_enable, GPIOF_OUT_INIT_HIGH, "sky81452-en"); - if (IS_ERR_VALUE(ret)) { + if (ret < 0) { dev_err(dev, "failed to request GPIO. err=%d\n", ret); return ret; } } ret = sky81452_bl_init_device(regmap, pdata); - if (IS_ERR_VALUE(ret)) { + if (ret < 0) { dev_err(dev, "failed to initialize. err=%d\n", ret); return ret; } @@ -302,8 +302,8 @@ static int sky81452_bl_probe(struct platform_device *pdev) platform_set_drvdata(pdev, bd); - ret = sysfs_create_group(&bd->dev.kobj, &sky81452_bl_attr_group); - if (IS_ERR_VALUE(ret)) { + ret = sysfs_create_group(&bd->dev.kobj, &sky81452_bl_attr_group); + if (ret < 0) { dev_err(dev, "failed to create attribute. err=%d\n", ret); return ret; } diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c index 3ad676558..83742d806 100644 --- a/drivers/video/backlight/tosa_bl.c +++ b/drivers/video/backlight/tosa_bl.c @@ -158,6 +158,7 @@ static const struct i2c_device_id tosa_bl_id[] = { { "tosa-bl", 0 }, { }, }; +MODULE_DEVICE_TABLE(i2c, tosa_bl_id); static struct i2c_driver tosa_bl_driver = { .driver = { diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index ba97efc3b..38da6e299 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -9,7 +9,7 @@ config VGA_CONSOLE depends on !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && \ !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && !CRIS && \ (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) && \ - !ARM64 + !ARM64 && !ARC && !MICROBLAZE default y help Saying Y here will allow you to use Linux in text mode through a diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 1aaf89300..92f394927 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -1093,6 +1093,7 @@ static void fbcon_init(struct vc_data *vc, int init) con_copy_unimap(vc, svc); ops = info->fbcon_par; + ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); p->con_rotate = initial_rotation; set_blitting_type(vc, info); diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index f88856156..8b1d371b5 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -2464,7 +2464,7 @@ config FB_SSD1307 tristate "Solomon SSD1307 framebuffer support" depends on FB && I2C depends on OF - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST select FB_SYS_FOPS select FB_SYS_FILLRECT select FB_SYS_COPYAREA @@ -2475,3 +2475,17 @@ config FB_SSD1307 help This driver implements support for the Solomon SSD1307 OLED controller over I2C. + +config FB_SM712 + tristate "Silicon Motion SM712 framebuffer support" + depends on FB && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + help + Frame buffer driver for the Silicon Motion SM710, SM712, SM721 + and SM722 chips. + + This driver is also available as a module. The module will be + called sm712fb. If you want to compile it as a module, say M + here and read <file:Documentation/kbuild/modules.txt>. diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile index cecea5063..50ed1b4fc 100644 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -131,6 +131,7 @@ obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o obj-$(CONFIG_FB_HYPERV) += hyperv_fb.o obj-$(CONFIG_FB_OPENCORES) += ocfb.o +obj-$(CONFIG_FB_SM712) += sm712fb.o # Platform or fallback drivers go here obj-$(CONFIG_FB_UVESA) += uvesafb.o diff --git a/drivers/video/fbdev/arkfb.c b/drivers/video/fbdev/arkfb.c index b305a1e7c..6a317de70 100644 --- a/drivers/video/fbdev/arkfb.c +++ b/drivers/video/fbdev/arkfb.c @@ -26,13 +26,9 @@ #include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */ #include <video/vga.h> -#ifdef CONFIG_MTRR -#include <asm/mtrr.h> -#endif - struct arkfb_info { int mclk_freq; - int mtrr_reg; + int wc_cookie; struct dac_info *dac; struct vgastate state; @@ -102,10 +98,6 @@ static const struct svga_timing_regs ark_timing_regs = { static char *mode_option = "640x480-8@60"; -#ifdef CONFIG_MTRR -static int mtrr = 1; -#endif - MODULE_AUTHOR("(c) 2007 Ondrej Zajicek <santiago@crfreenet.org>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("fbdev driver for ARK 2000PV"); @@ -115,11 +107,6 @@ MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)"); module_param_named(mode, mode_option, charp, 0444); MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc) (deprecated)"); -#ifdef CONFIG_MTRR -module_param(mtrr, int, 0444); -MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)"); -#endif - static int threshold = 4; module_param(threshold, int, 0644); @@ -1002,7 +989,7 @@ static int ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) info->fix.smem_len = pci_resource_len(dev, 0); /* Map physical IO memory address into kernel space */ - info->screen_base = pci_iomap(dev, 0, 0); + info->screen_base = pci_iomap_wc(dev, 0, 0); if (! info->screen_base) { rc = -ENOMEM; dev_err(info->device, "iomap for framebuffer failed\n"); @@ -1057,14 +1044,8 @@ static int ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) /* Record a reference to the driver data */ pci_set_drvdata(dev, info); - -#ifdef CONFIG_MTRR - if (mtrr) { - par->mtrr_reg = -1; - par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1); - } -#endif - + par->wc_cookie = arch_phys_wc_add(info->fix.smem_start, + info->fix.smem_len); return 0; /* Error handling */ @@ -1092,14 +1073,7 @@ static void ark_pci_remove(struct pci_dev *dev) if (info) { struct arkfb_info *par = info->par; - -#ifdef CONFIG_MTRR - if (par->mtrr_reg >= 0) { - mtrr_del(par->mtrr_reg, 0, 0); - par->mtrr_reg = -1; - } -#endif - + arch_phys_wc_del(par->wc_cookie); dac_release(par->dac); unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index abadc490f..19eb42b57 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -19,7 +19,6 @@ #include <linux/backlight.h> #include <linux/gfp.h> #include <linux/module.h> -#include <linux/platform_data/atmel.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_gpio.h> @@ -999,7 +998,7 @@ static const char *atmel_lcdfb_wiring_modes[] = { [ATMEL_LCDC_WIRING_RGB] = "RGB", }; -const int atmel_lcdfb_get_of_wiring_modes(struct device_node *np) +static int atmel_lcdfb_get_of_wiring_modes(struct device_node *np) { const char *mode; int err, i; diff --git a/drivers/video/fbdev/aty/atyfb.h b/drivers/video/fbdev/aty/atyfb.h index 1f39a62f8..63c4842eb 100644 --- a/drivers/video/fbdev/aty/atyfb.h +++ b/drivers/video/fbdev/aty/atyfb.h @@ -182,10 +182,7 @@ struct atyfb_par { unsigned long irq_flags; unsigned int irq; spinlock_t int_lock; -#ifdef CONFIG_MTRR - int mtrr_aper; - int mtrr_reg; -#endif + int wc_cookie; u32 mem_cntl; struct crtc saved_crtc; union aty_pll saved_pll; diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c index 8789e487b..f34ed47fc 100644 --- a/drivers/video/fbdev/aty/atyfb_base.c +++ b/drivers/video/fbdev/aty/atyfb_base.c @@ -98,9 +98,6 @@ #ifdef CONFIG_PMAC_BACKLIGHT #include <asm/backlight.h> #endif -#ifdef CONFIG_MTRR -#include <asm/mtrr.h> -#endif /* * Debug flags. @@ -303,9 +300,7 @@ static struct fb_ops atyfb_ops = { }; static bool noaccel; -#ifdef CONFIG_MTRR static bool nomtrr; -#endif static int vram; static int pll; static int mclk; @@ -427,6 +422,20 @@ static struct { #endif /* CONFIG_FB_ATY_CT */ }; +/* + * Last page of 8 MB (4 MB on ISA) aperture is MMIO, + * unless the auxiliary register aperture is used. + */ +static void aty_fudge_framebuffer_len(struct fb_info *info) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + + if (!par->aux_start && + (info->fix.smem_len == 0x800000 || + (par->bus_type == ISA && info->fix.smem_len == 0x400000))) + info->fix.smem_len -= GUI_RESERVE; +} + static int correct_chipset(struct atyfb_par *par) { u8 rev; @@ -2603,14 +2612,7 @@ static int aty_init(struct fb_info *info) if (par->pll_ops->resume_pll) par->pll_ops->resume_pll(info, &par->pll); - /* - * Last page of 8 MB (4 MB on ISA) aperture is MMIO, - * unless the auxiliary register aperture is used. - */ - if (!par->aux_start && - (info->fix.smem_len == 0x800000 || - (par->bus_type == ISA && info->fix.smem_len == 0x400000))) - info->fix.smem_len -= GUI_RESERVE; + aty_fudge_framebuffer_len(info); /* * Disable register access through the linear aperture @@ -2621,25 +2623,13 @@ static int aty_init(struct fb_info *info) aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, par) | BUS_APER_REG_DIS, par); -#ifdef CONFIG_MTRR - par->mtrr_aper = -1; - par->mtrr_reg = -1; - if (!nomtrr) { - /* Cover the whole resource. */ - par->mtrr_aper = mtrr_add(par->res_start, par->res_size, - MTRR_TYPE_WRCOMB, 1); - if (par->mtrr_aper >= 0 && !par->aux_start) { - /* Make a hole for mmio. */ - par->mtrr_reg = mtrr_add(par->res_start + 0x800000 - - GUI_RESERVE, GUI_RESERVE, - MTRR_TYPE_UNCACHABLE, 1); - if (par->mtrr_reg < 0) { - mtrr_del(par->mtrr_aper, 0, 0); - par->mtrr_aper = -1; - } - } - } -#endif + if (!nomtrr) + /* + * Only the ioremap_wc()'d area will get WC here + * since ioremap_uc() was used on the entire PCI BAR. + */ + par->wc_cookie = arch_phys_wc_add(par->res_start, + par->res_size); info->fbops = &atyfb_ops; info->pseudo_palette = par->pseudo_palette; @@ -2767,17 +2757,8 @@ aty_init_exit: /* restore video mode */ aty_set_crtc(par, &par->saved_crtc); par->pll_ops->set_pll(info, &par->saved_pll); + arch_phys_wc_del(par->wc_cookie); -#ifdef CONFIG_MTRR - if (par->mtrr_reg >= 0) { - mtrr_del(par->mtrr_reg, 0, 0); - par->mtrr_reg = -1; - } - if (par->mtrr_aper >= 0) { - mtrr_del(par->mtrr_aper, 0, 0); - par->mtrr_aper = -1; - } -#endif return ret; } @@ -3459,7 +3440,11 @@ static int atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info, } info->fix.mmio_start = raddr; - par->ati_regbase = ioremap(info->fix.mmio_start, 0x1000); + /* + * By using strong UC we force the MTRR to never have an + * effect on the MMIO region on both non-PAT and PAT systems. + */ + par->ati_regbase = ioremap_uc(info->fix.mmio_start, 0x1000); if (par->ati_regbase == NULL) return -ENOMEM; @@ -3482,7 +3467,24 @@ static int atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info, /* Map in frame buffer */ info->fix.smem_start = addr; - info->screen_base = ioremap(addr, 0x800000); + + /* + * The framebuffer is not always 8 MiB, that's just the size of the + * PCI BAR. We temporarily abuse smem_len here to store the size + * of the BAR. aty_init() will later correct it to match the actual + * framebuffer size. + * + * On devices that don't have the auxiliary register aperture, the + * registers are housed at the top end of the framebuffer PCI BAR. + * aty_fudge_framebuffer_len() is used to reduce smem_len to not + * overlap with the registers. + */ + info->fix.smem_len = 0x800000; + + aty_fudge_framebuffer_len(info); + + info->screen_base = ioremap_wc(info->fix.smem_start, + info->fix.smem_len); if (info->screen_base == NULL) { ret = -ENOMEM; goto atyfb_setup_generic_fail; @@ -3554,6 +3556,7 @@ static int atyfb_pci_probe(struct pci_dev *pdev, return -ENOMEM; } par = info->par; + par->bus_type = PCI; info->fix = atyfb_fix; info->device = &pdev->dev; par->pci_id = pdev->device; @@ -3655,7 +3658,8 @@ static int __init atyfb_atari_probe(void) * Map the video memory (physical address given) * to somewhere in the kernel address space. */ - info->screen_base = ioremap(phys_vmembase[m64_num], phys_size[m64_num]); + info->screen_base = ioremap_wc(phys_vmembase[m64_num], + phys_size[m64_num]); info->fix.smem_start = (unsigned long)info->screen_base; /* Fake! */ par->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000) + 0xFC00ul; @@ -3721,17 +3725,8 @@ static void atyfb_remove(struct fb_info *info) if (M64_HAS(MOBIL_BUS)) aty_bl_exit(info->bl_dev); #endif + arch_phys_wc_del(par->wc_cookie); -#ifdef CONFIG_MTRR - if (par->mtrr_reg >= 0) { - mtrr_del(par->mtrr_reg, 0, 0); - par->mtrr_reg = -1; - } - if (par->mtrr_aper >= 0) { - mtrr_del(par->mtrr_aper, 0, 0); - par->mtrr_aper = -1; - } -#endif #ifndef __sparc__ if (par->ati_regbase) iounmap(par->ati_regbase); @@ -3847,10 +3842,8 @@ static int __init atyfb_setup(char *options) while ((this_opt = strsep(&options, ",")) != NULL) { if (!strncmp(this_opt, "noaccel", 7)) { noaccel = 1; -#ifdef CONFIG_MTRR } else if (!strncmp(this_opt, "nomtrr", 6)) { nomtrr = 1; -#endif } else if (!strncmp(this_opt, "vram:", 5)) vram = simple_strtoul(this_opt + 5, NULL, 0); else if (!strncmp(this_opt, "pll:", 4)) @@ -4020,7 +4013,5 @@ module_param(comp_sync, int, 0); MODULE_PARM_DESC(comp_sync, "Set composite sync signal to low (0) or high (1)"); module_param(mode, charp, 0); MODULE_PARM_DESC(mode, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); -#ifdef CONFIG_MTRR module_param(nomtrr, bool, 0); MODULE_PARM_DESC(nomtrr, "bool: disable use of MTRR registers"); -#endif diff --git a/drivers/video/fbdev/broadsheetfb.c b/drivers/video/fbdev/broadsheetfb.c index 0e5fde1d3..9f9a7bef1 100644 --- a/drivers/video/fbdev/broadsheetfb.c +++ b/drivers/video/fbdev/broadsheetfb.c @@ -752,7 +752,7 @@ static ssize_t broadsheet_loadstore_waveform(struct device *dev, if ((fw_entry->size < 8*1024) || (fw_entry->size > 64*1024)) { dev_err(dev, "Invalid waveform\n"); err = -EINVAL; - goto err_failed; + goto err_fw; } mutex_lock(&(par->io_lock)); @@ -762,13 +762,15 @@ static ssize_t broadsheet_loadstore_waveform(struct device *dev, mutex_unlock(&(par->io_lock)); if (err < 0) { dev_err(dev, "Failed to store broadsheet waveform\n"); - goto err_failed; + goto err_fw; } dev_info(dev, "Stored broadsheet waveform, size %zd\n", fw_entry->size); - return len; + err = len; +err_fw: + release_firmware(fw_entry); err_failed: return err; } diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c index d787533d9..47c3191ec 100644 --- a/drivers/video/fbdev/core/fbmon.c +++ b/drivers/video/fbdev/core/fbmon.c @@ -1072,9 +1072,9 @@ void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) for (i = specs->modedb_len + num; i < specs->modedb_len + num + svd_n; i++) { int idx = svd[i - specs->modedb_len - num]; - if (!idx || idx > 63) { + if (!idx || idx >= ARRAY_SIZE(cea_modes)) { pr_warning("Reserved SVD code %d\n", idx); - } else if (idx > ARRAY_SIZE(cea_modes) || !cea_modes[idx].xres) { + } else if (!cea_modes[idx].xres) { pr_warning("Unimplemented SVD code %d\n", idx); } else { memcpy(&m[i], cea_modes + idx, sizeof(m[i])); diff --git a/drivers/video/fbdev/core/fbsysfs.c b/drivers/video/fbdev/core/fbsysfs.c index 60c3f0a16..15755ce1d 100644 --- a/drivers/video/fbdev/core/fbsysfs.c +++ b/drivers/video/fbdev/core/fbsysfs.c @@ -485,7 +485,7 @@ static ssize_t show_bl_curve(struct device *device, mutex_lock(&fb_info->bl_curve_mutex); for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8) - len += snprintf(&buf[len], PAGE_SIZE, "%8ph\n", + len += scnprintf(&buf[len], PAGE_SIZE - len, "%8ph\n", fb_info->bl_curve + i); mutex_unlock(&fb_info->bl_curve_mutex); diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c index 7d07cf824..2510fa728 100644 --- a/drivers/video/fbdev/core/modedb.c +++ b/drivers/video/fbdev/core/modedb.c @@ -289,7 +289,7 @@ static const struct fb_videomode modedb[] = { }; #ifdef CONFIG_FB_MODE_HELPERS -const struct fb_videomode cea_modes[64] = { +const struct fb_videomode cea_modes[65] = { /* #1: 640x480p@59.94/60Hz */ [1] = { NULL, 60, 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0, diff --git a/drivers/video/fbdev/ep93xx-fb.c b/drivers/video/fbdev/ep93xx-fb.c index 7ec251cc9..5b1081030 100644 --- a/drivers/video/fbdev/ep93xx-fb.c +++ b/drivers/video/fbdev/ep93xx-fb.c @@ -419,36 +419,15 @@ static struct fb_ops ep93xxfb_ops = { .fb_mmap = ep93xxfb_mmap, }; -static int ep93xxfb_calc_fbsize(struct ep93xxfb_mach_info *mach_info) -{ - int i, fb_size = 0; - - if (mach_info->num_modes == EP93XXFB_USE_MODEDB) { - fb_size = EP93XXFB_MAX_XRES * EP93XXFB_MAX_YRES * - mach_info->bpp / 8; - } else { - for (i = 0; i < mach_info->num_modes; i++) { - const struct fb_videomode *mode; - int size; - - mode = &mach_info->modes[i]; - size = mode->xres * mode->yres * mach_info->bpp / 8; - if (size > fb_size) - fb_size = size; - } - } - - return fb_size; -} - static int ep93xxfb_alloc_videomem(struct fb_info *info) { - struct ep93xx_fbi *fbi = info->par; char __iomem *virt_addr; dma_addr_t phys_addr; unsigned int fb_size; - fb_size = ep93xxfb_calc_fbsize(fbi->mach_info); + /* Maximum 16bpp -> used memory is maximum x*y*2 bytes */ + fb_size = EP93XXFB_MAX_XRES * EP93XXFB_MAX_YRES * 2; + virt_addr = dma_alloc_writecombine(info->dev, fb_size, &phys_addr, GFP_KERNEL); if (!virt_addr) @@ -550,8 +529,7 @@ static int ep93xxfb_probe(struct platform_device *pdev) fb_get_options("ep93xx-fb", &video_mode); err = fb_find_mode(&info->var, info, video_mode, - fbi->mach_info->modes, fbi->mach_info->num_modes, - fbi->mach_info->default_mode, fbi->mach_info->bpp); + NULL, 0, NULL, 16); if (err == 0) { dev_err(info->dev, "No suitable video mode found\n"); err = -EINVAL; diff --git a/drivers/video/fbdev/fsl-diu-fb.c b/drivers/video/fbdev/fsl-diu-fb.c index 7fa2e6f9e..b335c1ae8 100644 --- a/drivers/video/fbdev/fsl-diu-fb.c +++ b/drivers/video/fbdev/fsl-diu-fb.c @@ -1628,9 +1628,16 @@ static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state) static int fsl_diu_resume(struct platform_device *ofdev) { struct fsl_diu_data *data; + unsigned int i; data = dev_get_drvdata(&ofdev->dev); - enable_lcdc(data->fsl_diu_info); + + fsl_diu_enable_interrupts(data); + update_lcdc(data->fsl_diu_info); + for (i = 0; i < NUM_AOIS; i++) { + if (data->mfb[i].count) + fsl_diu_enable_panel(&data->fsl_diu_info[i]); + } return 0; } diff --git a/drivers/video/fbdev/gxt4500.c b/drivers/video/fbdev/gxt4500.c index 135d78a02..f19133a80 100644 --- a/drivers/video/fbdev/gxt4500.c +++ b/drivers/video/fbdev/gxt4500.c @@ -662,7 +662,7 @@ static int gxt4500_probe(struct pci_dev *pdev, const struct pci_device_id *ent) info->fix.smem_start = fb_phys; info->fix.smem_len = pci_resource_len(pdev, 1); - info->screen_base = pci_ioremap_bar(pdev, 1); + info->screen_base = pci_ioremap_wc_bar(pdev, 1); if (!info->screen_base) { dev_err(&pdev->dev, "gxt4500: cannot map framebuffer\n"); goto err_unmap_regs; diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index 807ee22ef..e2451bdb4 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -213,7 +213,7 @@ struct synthvid_msg { struct hvfb_par { struct fb_info *info; - struct resource mem; + struct resource *mem; bool fb_ready; /* fb device is ready */ struct completion wait; u32 synthvid_version; @@ -677,26 +677,18 @@ 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) +static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info) { struct hvfb_par *par = info->par; struct pci_dev *pdev = NULL; void __iomem *fb_virt; int gen2vm = efi_enabled(EFI_BOOT); + resource_size_t pot_start, pot_end; int ret; - 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; - } + pot_start = 0; + pot_end = -1; } else { pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT, PCI_DEVICE_ID_HYPERV_VIDEO, NULL); @@ -709,16 +701,18 @@ static int hvfb_getmem(struct fb_info *info) pci_resource_len(pdev, 0) < screen_fb_size) 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; - } + pot_end = pci_resource_end(pdev, 0); + pot_start = pot_end - screen_fb_size + 1; + } + + ret = vmbus_allocate_mmio(&par->mem, hdev, pot_start, pot_end, + screen_fb_size, 0x100000, true); + if (ret != 0) { + pr_err("Unable to allocate framebuffer memory\n"); + goto err1; } - fb_virt = ioremap(par->mem.start, screen_fb_size); + fb_virt = ioremap(par->mem->start, screen_fb_size); if (!fb_virt) goto err2; @@ -736,7 +730,7 @@ static int hvfb_getmem(struct fb_info *info) info->apertures->ranges[0].size = pci_resource_len(pdev, 0); } - info->fix.smem_start = par->mem.start; + 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; @@ -749,7 +743,8 @@ static int hvfb_getmem(struct fb_info *info) err3: iounmap(fb_virt); err2: - release_resource(&par->mem); + release_mem_region(par->mem->start, screen_fb_size); + par->mem = NULL; err1: if (!gen2vm) pci_dev_put(pdev); @@ -763,7 +758,8 @@ static void hvfb_putmem(struct fb_info *info) struct hvfb_par *par = info->par; iounmap(info->screen_base); - release_resource(&par->mem); + release_mem_region(par->mem->start, screen_fb_size); + par->mem = NULL; } @@ -794,7 +790,7 @@ static int hvfb_probe(struct hv_device *hdev, goto error1; } - ret = hvfb_getmem(info); + ret = hvfb_getmem(hdev, info); if (ret) { pr_err("No memory for framebuffer\n"); goto error2; diff --git a/drivers/video/fbdev/i740fb.c b/drivers/video/fbdev/i740fb.c index a2b4204b4..452e1163a 100644 --- a/drivers/video/fbdev/i740fb.c +++ b/drivers/video/fbdev/i740fb.c @@ -27,24 +27,15 @@ #include <linux/console.h> #include <video/vga.h> -#ifdef CONFIG_MTRR -#include <asm/mtrr.h> -#endif - #include "i740_reg.h" static char *mode_option; - -#ifdef CONFIG_MTRR static int mtrr = 1; -#endif struct i740fb_par { unsigned char __iomem *regs; bool has_sgram; -#ifdef CONFIG_MTRR - int mtrr_reg; -#endif + int wc_cookie; bool ddc_registered; struct i2c_adapter ddc_adapter; struct i2c_algo_bit_data ddc_algo; @@ -1040,7 +1031,7 @@ static int i740fb_probe(struct pci_dev *dev, const struct pci_device_id *ent) goto err_request_regions; } - info->screen_base = pci_ioremap_bar(dev, 0); + info->screen_base = pci_ioremap_wc_bar(dev, 0); if (!info->screen_base) { dev_err(info->device, "error remapping base\n"); ret = -ENOMEM; @@ -1144,13 +1135,9 @@ static int i740fb_probe(struct pci_dev *dev, const struct pci_device_id *ent) fb_info(info, "%s frame buffer device\n", info->fix.id); pci_set_drvdata(dev, info); -#ifdef CONFIG_MTRR - if (mtrr) { - par->mtrr_reg = -1; - par->mtrr_reg = mtrr_add(info->fix.smem_start, - info->fix.smem_len, MTRR_TYPE_WRCOMB, 1); - } -#endif + if (mtrr) + par->wc_cookie = arch_phys_wc_add(info->fix.smem_start, + info->fix.smem_len); return 0; err_reg_framebuffer: @@ -1177,13 +1164,7 @@ static void i740fb_remove(struct pci_dev *dev) if (info) { struct i740fb_par *par = info->par; - -#ifdef CONFIG_MTRR - if (par->mtrr_reg >= 0) { - mtrr_del(par->mtrr_reg, 0, 0); - par->mtrr_reg = -1; - } -#endif + arch_phys_wc_del(par->wc_cookie); unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); if (par->ddc_registered) @@ -1287,10 +1268,8 @@ static int __init i740fb_setup(char *options) while ((opt = strsep(&options, ",")) != NULL) { if (!*opt) continue; -#ifdef CONFIG_MTRR else if (!strncmp(opt, "mtrr:", 5)) mtrr = simple_strtoul(opt + 5, NULL, 0); -#endif else mode_option = opt; } @@ -1327,7 +1306,5 @@ MODULE_DESCRIPTION("fbdev driver for Intel740"); module_param(mode_option, charp, 0444); MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)"); -#ifdef CONFIG_MTRR module_param(mtrr, int, 0444); MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)"); -#endif diff --git a/drivers/video/fbdev/kyro/fbdev.c b/drivers/video/fbdev/kyro/fbdev.c index 65041e15f..5bb015332 100644 --- a/drivers/video/fbdev/kyro/fbdev.c +++ b/drivers/video/fbdev/kyro/fbdev.c @@ -22,9 +22,6 @@ #include <linux/pci.h> #include <asm/io.h> #include <linux/uaccess.h> -#ifdef CONFIG_MTRR -#include <asm/mtrr.h> -#endif #include <video/kyro.h> @@ -84,9 +81,7 @@ static device_info_t deviceInfo; static char *mode_option = NULL; static int nopan = 0; static int nowrap = 1; -#ifdef CONFIG_MTRR static int nomtrr = 0; -#endif /* PCI driver prototypes */ static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent); @@ -570,10 +565,8 @@ static int __init kyrofb_setup(char *options) nopan = 1; } else if (strcmp(this_opt, "nowrap") == 0) { nowrap = 1; -#ifdef CONFIG_MTRR } else if (strcmp(this_opt, "nomtrr") == 0) { nomtrr = 1; -#endif } else { mode_option = this_opt; } @@ -691,17 +684,16 @@ static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) currentpar->regbase = deviceInfo.pSTGReg = ioremap_nocache(kyro_fix.mmio_start, kyro_fix.mmio_len); + if (!currentpar->regbase) + goto out_free_fb; - info->screen_base = ioremap_nocache(kyro_fix.smem_start, - kyro_fix.smem_len); + info->screen_base = pci_ioremap_wc_bar(pdev, 0); + if (!info->screen_base) + goto out_unmap_regs; -#ifdef CONFIG_MTRR if (!nomtrr) - currentpar->mtrr_handle = - mtrr_add(kyro_fix.smem_start, - kyro_fix.smem_len, - MTRR_TYPE_WRCOMB, 1); -#endif + currentpar->wc_cookie = arch_phys_wc_add(kyro_fix.smem_start, + kyro_fix.smem_len); kyro_fix.ypanstep = nopan ? 0 : 1; kyro_fix.ywrapstep = nowrap ? 0 : 1; @@ -745,8 +737,10 @@ static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return 0; out_unmap: - iounmap(currentpar->regbase); iounmap(info->screen_base); +out_unmap_regs: + iounmap(currentpar->regbase); +out_free_fb: framebuffer_release(info); return -EINVAL; @@ -770,12 +764,7 @@ static void kyrofb_remove(struct pci_dev *pdev) iounmap(info->screen_base); iounmap(par->regbase); -#ifdef CONFIG_MTRR - if (par->mtrr_handle) - mtrr_del(par->mtrr_handle, - info->fix.smem_start, - info->fix.smem_len); -#endif + arch_phys_wc_del(par->wc_cookie); unregister_framebuffer(info); framebuffer_release(info); diff --git a/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c b/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c index 9b8bebdf8..f9ec5c048 100644 --- a/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c +++ b/drivers/video/fbdev/mb862xx/mb862xxfbdrv.c @@ -831,6 +831,7 @@ static struct of_device_id of_platform_mb862xx_tbl[] = { { .compatible = "fujitsu,coral", }, { /* end */ } }; +MODULE_DEVICE_TABLE(of, of_platform_mb862xx_tbl); static struct platform_driver of_platform_mb862xxfb_driver = { .driver = { diff --git a/drivers/video/fbdev/ocfb.c b/drivers/video/fbdev/ocfb.c index de9819660..c9293aea8 100644 --- a/drivers/video/fbdev/ocfb.c +++ b/drivers/video/fbdev/ocfb.c @@ -325,7 +325,6 @@ static int ocfb_probe(struct platform_device *pdev) dev_err(&pdev->dev, "I/O resource request failed\n"); return -ENXIO; } - res->flags &= ~IORESOURCE_CACHEABLE; fbdev->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(fbdev->regs)) return PTR_ERR(fbdev->regs); diff --git a/drivers/video/fbdev/omap2/displays-new/connector-dvi.c b/drivers/video/fbdev/omap2/displays-new/connector-dvi.c index a8ce920fa..d811e6dca 100644 --- a/drivers/video/fbdev/omap2/displays-new/connector-dvi.c +++ b/drivers/video/fbdev/omap2/displays-new/connector-dvi.c @@ -294,7 +294,7 @@ static int dvic_probe_of(struct platform_device *pdev) adapter_node = of_parse_phandle(node, "ddc-i2c-bus", 0); if (adapter_node) { - adapter = of_find_i2c_adapter_by_node(adapter_node); + adapter = of_get_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); diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c b/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c index a14d993f7..8c246c213 100644 --- a/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c +++ b/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c @@ -266,7 +266,6 @@ static struct platform_driver opa362_driver = { .remove = __exit_p(opa362_remove), .driver = { .name = "amplifier-opa362", - .owner = THIS_MODULE, .of_match_table = opa362_of_match, .suppress_bind_attrs = true, }, diff --git a/drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c b/drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c index 90cbc4c34..c581231c7 100644 --- a/drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c +++ b/drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c @@ -898,6 +898,7 @@ static const struct of_device_id acx565akm_of_match[] = { { .compatible = "omapdss,sony,acx565akm", }, {}, }; +MODULE_DEVICE_TABLE(of, acx565akm_of_match); static struct spi_driver acx565akm_driver = { .driver = { diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c index 4f0cbb54d..d3af01c94 100644 --- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c @@ -1091,7 +1091,7 @@ static void mmap_user_close(struct vm_area_struct *vma) omapfb_put_mem_region(rg); } -static struct vm_operations_struct mmap_user_ops = { +static const struct vm_operations_struct mmap_user_ops = { .open = mmap_user_open, .close = mmap_user_close, }; diff --git a/drivers/video/fbdev/pxa168fb.c b/drivers/video/fbdev/pxa168fb.c index e209b039f..efb57c059 100644 --- a/drivers/video/fbdev/pxa168fb.c +++ b/drivers/video/fbdev/pxa168fb.c @@ -615,7 +615,7 @@ static int pxa168fb_probe(struct platform_device *pdev) return -EINVAL; } - clk = clk_get(&pdev->dev, "LCDCLK"); + clk = devm_clk_get(&pdev->dev, "LCDCLK"); if (IS_ERR(clk)) { dev_err(&pdev->dev, "unable to get LCDCLK"); return PTR_ERR(clk); @@ -624,21 +624,18 @@ static int pxa168fb_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "no IO memory defined\n"); - ret = -ENOENT; - goto failed_put_clk; + return -ENOENT; } irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "no IRQ defined\n"); - ret = -ENOENT; - goto failed_put_clk; + return -ENOENT; } info = framebuffer_alloc(sizeof(struct pxa168fb_info), &pdev->dev); if (info == NULL) { - ret = -ENOMEM; - goto failed_put_clk; + return -ENOMEM; } /* Initialize private data */ @@ -776,8 +773,6 @@ failed_free_fbmem: info->screen_base, fbi->fb_start_dma); failed_free_info: kfree(info); -failed_put_clk: - clk_put(clk); dev_err(&pdev->dev, "frame buffer device init failed with %d\n", ret); return ret; @@ -813,7 +808,6 @@ static int pxa168fb_remove(struct platform_device *pdev) info->screen_base, info->fix.smem_start); clk_disable(fbi->clk); - clk_put(fbi->clk); framebuffer_release(info); diff --git a/drivers/video/fbdev/pxafb.c b/drivers/video/fbdev/pxafb.c index 7245611ec..94813af97 100644 --- a/drivers/video/fbdev/pxafb.c +++ b/drivers/video/fbdev/pxafb.c @@ -1668,7 +1668,6 @@ pxafb_freq_policy(struct notifier_block *nb, unsigned long val, void *data) switch (val) { case CPUFREQ_ADJUST: - case CPUFREQ_INCOMPATIBLE: pr_debug("min dma period: %d ps, " "new clock %d kHz\n", pxafb_display_dma_period(var), policy->max); diff --git a/drivers/video/fbdev/s1d13xxxfb.c b/drivers/video/fbdev/s1d13xxxfb.c index 83433cb0d..96aa46dc6 100644 --- a/drivers/video/fbdev/s1d13xxxfb.c +++ b/drivers/video/fbdev/s1d13xxxfb.c @@ -32,8 +32,7 @@ #include <linux/spinlock_types.h> #include <linux/spinlock.h> #include <linux/slab.h> - -#include <asm/io.h> +#include <linux/io.h> #include <video/s1d13xxxfb.h> diff --git a/drivers/video/fbdev/s3c-fb.c b/drivers/video/fbdev/s3c-fb.c index 7e3a05fc4..f72dd1245 100644 --- a/drivers/video/fbdev/s3c-fb.c +++ b/drivers/video/fbdev/s3c-fb.c @@ -1938,7 +1938,7 @@ static struct s3c_fb_driverdata s3c_fb_data_s3c2443 = { }, }; -static struct platform_device_id s3c_fb_driver_ids[] = { +static const struct platform_device_id s3c_fb_driver_ids[] = { { .name = "s3c-fb", .driver_data = (unsigned long)&s3c_fb_data_64xx, diff --git a/drivers/video/fbdev/s3fb.c b/drivers/video/fbdev/s3fb.c index f0ae61a37..13b109073 100644 --- a/drivers/video/fbdev/s3fb.c +++ b/drivers/video/fbdev/s3fb.c @@ -28,13 +28,9 @@ #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> -#ifdef CONFIG_MTRR -#include <asm/mtrr.h> -#endif - struct s3fb_info { int chip, rev, mclk_freq; - int mtrr_reg; + int wc_cookie; struct vgastate state; struct mutex open_lock; unsigned int ref_count; @@ -154,11 +150,7 @@ static const struct svga_timing_regs s3_timing_regs = { static char *mode_option; - -#ifdef CONFIG_MTRR static int mtrr = 1; -#endif - static int fasttext = 1; @@ -170,11 +162,8 @@ module_param(mode_option, charp, 0444); MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)"); module_param_named(mode, mode_option, charp, 0444); MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc) (deprecated)"); - -#ifdef CONFIG_MTRR module_param(mtrr, int, 0444); MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)"); -#endif module_param(fasttext, int, 0644); MODULE_PARM_DESC(fasttext, "Enable S3 fast text mode (1=enable, 0=disable, default=1)"); @@ -1168,7 +1157,7 @@ static int s3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) info->fix.smem_len = pci_resource_len(dev, 0); /* Map physical IO memory address into kernel space */ - info->screen_base = pci_iomap(dev, 0, 0); + info->screen_base = pci_iomap_wc(dev, 0, 0); if (! info->screen_base) { rc = -ENOMEM; dev_err(info->device, "iomap for framebuffer failed\n"); @@ -1365,12 +1354,9 @@ static int s3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) /* Record a reference to the driver data */ pci_set_drvdata(dev, info); -#ifdef CONFIG_MTRR - if (mtrr) { - par->mtrr_reg = -1; - par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1); - } -#endif + if (mtrr) + par->wc_cookie = arch_phys_wc_add(info->fix.smem_start, + info->fix.smem_len); return 0; @@ -1405,14 +1391,7 @@ static void s3_pci_remove(struct pci_dev *dev) if (info) { par = info->par; - -#ifdef CONFIG_MTRR - if (par->mtrr_reg >= 0) { - mtrr_del(par->mtrr_reg, 0, 0); - par->mtrr_reg = -1; - } -#endif - + arch_phys_wc_del(par->wc_cookie); unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); @@ -1551,10 +1530,8 @@ static int __init s3fb_setup(char *options) if (!*opt) continue; -#ifdef CONFIG_MTRR else if (!strncmp(opt, "mtrr:", 5)) mtrr = simple_strtoul(opt + 5, NULL, 0); -#endif else if (!strncmp(opt, "fasttext:", 9)) fasttext = simple_strtoul(opt + 9, NULL, 0); else diff --git a/drivers/video/fbdev/sa1100fb.c b/drivers/video/fbdev/sa1100fb.c index 89dd7e021..dcf774c15 100644 --- a/drivers/video/fbdev/sa1100fb.c +++ b/drivers/video/fbdev/sa1100fb.c @@ -1042,7 +1042,6 @@ sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val, switch (val) { case CPUFREQ_ADJUST: - case CPUFREQ_INCOMPATIBLE: dev_dbg(fbi->dev, "min dma period: %d ps, " "new clock %d kHz\n", sa1100fb_min_dma_period(fbi), policy->max); diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c index 1085c0432..52c5c7e63 100644 --- a/drivers/video/fbdev/simplefb.c +++ b/drivers/video/fbdev/simplefb.c @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/platform_data/simplefb.h> #include <linux/platform_device.h> +#include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/of_platform.h> diff --git a/drivers/video/fbdev/sm712.h b/drivers/video/fbdev/sm712.h new file mode 100644 index 000000000..aad1cc4be --- /dev/null +++ b/drivers/video/fbdev/sm712.h @@ -0,0 +1,116 @@ +/* + * Silicon Motion SM712 frame buffer device + * + * Copyright (C) 2006 Silicon Motion Technology Corp. + * Authors: Ge Wang, gewang@siliconmotion.com + * Boyod boyod.yang@siliconmotion.com.cn + * + * Copyright (C) 2009 Lemote, Inc. + * Author: Wu Zhangjin, wuzhangjin@gmail.com + * + * 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. + */ + +#define FB_ACCEL_SMI_LYNX 88 + +#define SCREEN_X_RES 1024 +#define SCREEN_Y_RES 600 +#define SCREEN_BPP 16 + +/*Assume SM712 graphics chip has 4MB VRAM */ +#define SM712_VIDEOMEMORYSIZE 0x00400000 +/*Assume SM722 graphics chip has 8MB VRAM */ +#define SM722_VIDEOMEMORYSIZE 0x00800000 + +#define dac_reg (0x3c8) +#define dac_val (0x3c9) + +extern void __iomem *smtc_regbaseaddress; +#define smtc_mmiowb(dat, reg) writeb(dat, smtc_regbaseaddress + reg) + +#define smtc_mmiorb(reg) readb(smtc_regbaseaddress + reg) + +#define SIZE_SR00_SR04 (0x04 - 0x00 + 1) +#define SIZE_SR10_SR24 (0x24 - 0x10 + 1) +#define SIZE_SR30_SR75 (0x75 - 0x30 + 1) +#define SIZE_SR80_SR93 (0x93 - 0x80 + 1) +#define SIZE_SRA0_SRAF (0xAF - 0xA0 + 1) +#define SIZE_GR00_GR08 (0x08 - 0x00 + 1) +#define SIZE_AR00_AR14 (0x14 - 0x00 + 1) +#define SIZE_CR00_CR18 (0x18 - 0x00 + 1) +#define SIZE_CR30_CR4D (0x4D - 0x30 + 1) +#define SIZE_CR90_CRA7 (0xA7 - 0x90 + 1) + +static inline void smtc_crtcw(int reg, int val) +{ + smtc_mmiowb(reg, 0x3d4); + smtc_mmiowb(val, 0x3d5); +} + +static inline void smtc_grphw(int reg, int val) +{ + smtc_mmiowb(reg, 0x3ce); + smtc_mmiowb(val, 0x3cf); +} + +static inline void smtc_attrw(int reg, int val) +{ + smtc_mmiorb(0x3da); + smtc_mmiowb(reg, 0x3c0); + smtc_mmiorb(0x3c1); + smtc_mmiowb(val, 0x3c0); +} + +static inline void smtc_seqw(int reg, int val) +{ + smtc_mmiowb(reg, 0x3c4); + smtc_mmiowb(val, 0x3c5); +} + +static inline unsigned int smtc_seqr(int reg) +{ + smtc_mmiowb(reg, 0x3c4); + return smtc_mmiorb(0x3c5); +} + +/* The next structure holds all information relevant for a specific video mode. + */ + +struct modeinit { + int mmsizex; + int mmsizey; + int bpp; + int hz; + unsigned char init_misc; + unsigned char init_sr00_sr04[SIZE_SR00_SR04]; + unsigned char init_sr10_sr24[SIZE_SR10_SR24]; + unsigned char init_sr30_sr75[SIZE_SR30_SR75]; + unsigned char init_sr80_sr93[SIZE_SR80_SR93]; + unsigned char init_sra0_sraf[SIZE_SRA0_SRAF]; + unsigned char init_gr00_gr08[SIZE_GR00_GR08]; + unsigned char init_ar00_ar14[SIZE_AR00_AR14]; + unsigned char init_cr00_cr18[SIZE_CR00_CR18]; + unsigned char init_cr30_cr4d[SIZE_CR30_CR4D]; + unsigned char init_cr90_cra7[SIZE_CR90_CRA7]; +}; + +#ifdef __BIG_ENDIAN +#define pal_rgb(r, g, b, val) (((r & 0xf800) >> 8) | \ + ((g & 0xe000) >> 13) | \ + ((g & 0x1c00) << 3) | \ + ((b & 0xf800) >> 3)) +#define big_addr 0x800000 +#define mmio_addr 0x00800000 +#define seqw17() smtc_seqw(0x17, 0x30) +#define big_pixel_depth(p, d) {if (p == 24) {p = 32; d = 32; } } +#define big_swap(p) ((p & 0xff00ff00 >> 8) | (p & 0x00ff00ff << 8)) +#else +#define pal_rgb(r, g, b, val) val +#define big_addr 0 +#define mmio_addr 0x00c00000 +#define seqw17() do { } while (0) +#define big_pixel_depth(p, d) do { } while (0) +#define big_swap(p) p +#endif diff --git a/drivers/video/fbdev/sm712fb.c b/drivers/video/fbdev/sm712fb.c new file mode 100644 index 000000000..629bfa2d2 --- /dev/null +++ b/drivers/video/fbdev/sm712fb.c @@ -0,0 +1,1653 @@ +/* + * Silicon Motion SM7XX frame buffer device + * + * Copyright (C) 2006 Silicon Motion Technology Corp. + * Authors: Ge Wang, gewang@siliconmotion.com + * Boyod boyod.yang@siliconmotion.com.cn + * + * Copyright (C) 2009 Lemote, Inc. + * Author: Wu Zhangjin, wuzhangjin@gmail.com + * + * Copyright (C) 2011 Igalia, S.L. + * Author: Javier M. Mellid <jmunhoz@igalia.com> + * + * 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. + * + * Framebuffer driver for Silicon Motion SM710, SM712, SM721 and SM722 chips + */ + +#include <linux/io.h> +#include <linux/fb.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/module.h> +#include <linux/console.h> +#include <linux/screen_info.h> + +#ifdef CONFIG_PM +#include <linux/pm.h> +#endif + +#include "sm712.h" + +/* +* Private structure +*/ +struct smtcfb_info { + struct pci_dev *pdev; + struct fb_info *fb; + u16 chip_id; + u8 chip_rev_id; + + void __iomem *lfb; /* linear frame buffer */ + void __iomem *dp_regs; /* drawing processor control regs */ + void __iomem *vp_regs; /* video processor control regs */ + void __iomem *cp_regs; /* capture processor control regs */ + void __iomem *mmio; /* memory map IO port */ + + u_int width; + u_int height; + u_int hz; + + u32 colreg[17]; +}; + +void __iomem *smtc_regbaseaddress; /* Memory Map IO starting address */ + +static struct fb_var_screeninfo smtcfb_var = { + .xres = 1024, + .yres = 600, + .xres_virtual = 1024, + .yres_virtual = 600, + .bits_per_pixel = 16, + .red = {16, 8, 0}, + .green = {8, 8, 0}, + .blue = {0, 8, 0}, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .vmode = FB_VMODE_NONINTERLACED, + .nonstd = 0, + .accel_flags = FB_ACCELF_TEXT, +}; + +static struct fb_fix_screeninfo smtcfb_fix = { + .id = "smXXXfb", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .line_length = 800 * 3, + .accel = FB_ACCEL_SMI_LYNX, + .type_aux = 0, + .xpanstep = 0, + .ypanstep = 0, + .ywrapstep = 0, +}; + +struct vesa_mode { + char index[6]; + u16 lfb_width; + u16 lfb_height; + u16 lfb_depth; +}; + +static const struct vesa_mode vesa_mode_table[] = { + {"0x301", 640, 480, 8}, + {"0x303", 800, 600, 8}, + {"0x305", 1024, 768, 8}, + {"0x307", 1280, 1024, 8}, + + {"0x311", 640, 480, 16}, + {"0x314", 800, 600, 16}, + {"0x317", 1024, 768, 16}, + {"0x31A", 1280, 1024, 16}, + + {"0x312", 640, 480, 24}, + {"0x315", 800, 600, 24}, + {"0x318", 1024, 768, 24}, + {"0x31B", 1280, 1024, 24}, +}; + +/********************************************************************** + SM712 Mode table. + **********************************************************************/ +static const struct modeinit vgamode[] = { + { + /* mode#0: 640 x 480 16Bpp 60Hz */ + 640, 480, 16, 60, + /* Init_MISC */ + 0xE3, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x00, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, + 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, + 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, + 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, + 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, + 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, + 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, + 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, + }, + { /* Init_CR90_CRA7 */ + 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, + 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, + 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, + }, + }, + { + /* mode#1: 640 x 480 24Bpp 60Hz */ + 640, 480, 24, 60, + /* Init_MISC */ + 0xE3, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x00, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, + 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, + 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, + 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, + 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, + 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, + 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, + 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, + }, + { /* Init_CR90_CRA7 */ + 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, + 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, + 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, + }, + }, + { + /* mode#0: 640 x 480 32Bpp 60Hz */ + 640, 480, 32, 60, + /* Init_MISC */ + 0xE3, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x00, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, + 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, + 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, + 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, + 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, + 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, + 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, + 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, + }, + { /* Init_CR90_CRA7 */ + 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, + 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, + 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, + }, + }, + + { /* mode#2: 800 x 600 16Bpp 60Hz */ + 800, 600, 16, 60, + /* Init_MISC */ + 0x2B, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, + 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, + 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, + 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, + 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, + 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, + 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, + 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, + }, + { /* Init_CR90_CRA7 */ + 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, + 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, + 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, + }, + }, + { /* mode#3: 800 x 600 24Bpp 60Hz */ + 800, 600, 24, 60, + 0x2B, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36, + 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, + 0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, + 0x02, 0x45, 0x30, 0x30, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36, + 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, + 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, + 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, + 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, + }, + { /* Init_CR90_CRA7 */ + 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, + 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, + 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, + }, + }, + { /* mode#7: 800 x 600 32Bpp 60Hz */ + 800, 600, 32, 60, + /* Init_MISC */ + 0x2B, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, + 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, + 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, + 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, + 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, + 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, + 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, + 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, + }, + { /* Init_CR90_CRA7 */ + 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, + 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, + 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, + }, + }, + /* We use 1024x768 table to light 1024x600 panel for lemote */ + { /* mode#4: 1024 x 600 16Bpp 60Hz */ + 1024, 600, 16, 60, + /* Init_MISC */ + 0xEB, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x00, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20, + 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x00, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22, + 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, + 0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22, + 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02, + 0x04, 0x45, 0x3F, 0x30, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, + 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, + 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, + 0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00, + 0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57, + }, + { /* Init_CR90_CRA7 */ + 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, + 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, + }, + }, + { /* mode#5: 1024 x 768 24Bpp 60Hz */ + 1024, 768, 24, 60, + /* Init_MISC */ + 0xEB, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, + 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, + 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, + 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, + 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, + 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, + 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, + 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, + 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, + }, + { /* Init_CR90_CRA7 */ + 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, + 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, + }, + }, + { /* mode#4: 1024 x 768 32Bpp 60Hz */ + 1024, 768, 32, 60, + /* Init_MISC */ + 0xEB, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x32, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, + 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, + 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, + 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, + 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, + 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, + 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, + 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, + 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, + }, + { /* Init_CR90_CRA7 */ + 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, + 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, + }, + }, + { /* mode#6: 320 x 240 16Bpp 60Hz */ + 320, 240, 16, 60, + /* Init_MISC */ + 0xEB, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x32, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, + 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, + 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, + 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, + 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, + 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, + 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, + 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, + 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, + 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, + }, + { /* Init_CR90_CRA7 */ + 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, + 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, + }, + }, + + { /* mode#8: 320 x 240 32Bpp 60Hz */ + 320, 240, 32, 60, + /* Init_MISC */ + 0xEB, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x32, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, + 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, + 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, + 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, + 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, + 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, + 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, + 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, + 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, + 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, + }, + { /* Init_CR90_CRA7 */ + 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, + 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, + }, + }, +}; + +static struct screen_info smtc_scr_info; + +static char *mode_option; + +/* process command line options, get vga parameter */ +static void __init sm7xx_vga_setup(char *options) +{ + int i; + + if (!options || !*options) + return; + + smtc_scr_info.lfb_width = 0; + smtc_scr_info.lfb_height = 0; + smtc_scr_info.lfb_depth = 0; + + pr_debug("sm7xx_vga_setup = %s\n", options); + + for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) { + if (strstr(options, vesa_mode_table[i].index)) { + smtc_scr_info.lfb_width = vesa_mode_table[i].lfb_width; + smtc_scr_info.lfb_height = + vesa_mode_table[i].lfb_height; + smtc_scr_info.lfb_depth = vesa_mode_table[i].lfb_depth; + return; + } + } +} + +static void sm712_setpalette(int regno, unsigned red, unsigned green, + unsigned blue, struct fb_info *info) +{ + /* set bit 5:4 = 01 (write LCD RAM only) */ + smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10); + + smtc_mmiowb(regno, dac_reg); + smtc_mmiowb(red >> 10, dac_val); + smtc_mmiowb(green >> 10, dac_val); + smtc_mmiowb(blue >> 10, dac_val); +} + +/* chan_to_field + * + * convert a colour value into a field position + * + * from pxafb.c + */ + +static inline unsigned int chan_to_field(unsigned int chan, + struct fb_bitfield *bf) +{ + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; +} + +static int smtc_blank(int blank_mode, struct fb_info *info) +{ + /* clear DPMS setting */ + switch (blank_mode) { + case FB_BLANK_UNBLANK: + /* Screen On: HSync: On, VSync : On */ + smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20))); + smtc_seqw(0x6a, 0x16); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77)); + smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30))); + smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0))); + smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01)); + smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03)); + break; + case FB_BLANK_NORMAL: + /* Screen Off: HSync: On, VSync : On Soft blank */ + smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20))); + smtc_seqw(0x6a, 0x16); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30))); + smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0))); + smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01)); + smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); + break; + case FB_BLANK_VSYNC_SUSPEND: + /* Screen On: HSync: On, VSync : Off */ + smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); + smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); + smtc_seqw(0x6a, 0x0c); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); + smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20)); + smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20)); + smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); + smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); + smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); + break; + case FB_BLANK_HSYNC_SUSPEND: + /* Screen On: HSync: Off, VSync : On */ + smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); + smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); + smtc_seqw(0x6a, 0x0c); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); + smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10)); + smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8)); + smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); + smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); + smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); + break; + case FB_BLANK_POWERDOWN: + /* Screen On: HSync: Off, VSync : Off */ + smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); + smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); + smtc_seqw(0x6a, 0x0c); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); + smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30)); + smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8)); + smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); + smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); + smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned trans, struct fb_info *info) +{ + struct smtcfb_info *sfb; + u32 val; + + sfb = info->par; + + if (regno > 255) + return 1; + + switch (sfb->fb->fix.visual) { + case FB_VISUAL_DIRECTCOLOR: + case FB_VISUAL_TRUECOLOR: + /* + * 16/32 bit true-colour, use pseudo-palette for 16 base color + */ + if (regno >= 16) + break; + if (sfb->fb->var.bits_per_pixel == 16) { + u32 *pal = sfb->fb->pseudo_palette; + + val = chan_to_field(red, &sfb->fb->var.red); + val |= chan_to_field(green, &sfb->fb->var.green); + val |= chan_to_field(blue, &sfb->fb->var.blue); + pal[regno] = pal_rgb(red, green, blue, val); + } else { + u32 *pal = sfb->fb->pseudo_palette; + + val = chan_to_field(red, &sfb->fb->var.red); + val |= chan_to_field(green, &sfb->fb->var.green); + val |= chan_to_field(blue, &sfb->fb->var.blue); + pal[regno] = big_swap(val); + } + break; + + case FB_VISUAL_PSEUDOCOLOR: + /* color depth 8 bit */ + sm712_setpalette(regno, red, green, blue, info); + break; + + default: + return 1; /* unknown type */ + } + + return 0; +} + +static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, + size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + + u32 *buffer, *dst; + u32 __iomem *src; + int c, i, cnt = 0, err = 0; + unsigned long total_size; + + if (!info || !info->screen_base) + return -ENODEV; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + total_size = info->screen_size; + + if (total_size == 0) + total_size = info->fix.smem_len; + + if (p >= total_size) + return 0; + + if (count >= total_size) + count = total_size; + + if (count + p > total_size) + count = total_size - p; + + buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + src = (u32 __iomem *)(info->screen_base + p); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + while (count) { + c = (count > PAGE_SIZE) ? PAGE_SIZE : count; + dst = buffer; + for (i = c >> 2; i--;) { + *dst = fb_readl(src++); + *dst = big_swap(*dst); + dst++; + } + if (c & 3) { + u8 *dst8 = (u8 *)dst; + u8 __iomem *src8 = (u8 __iomem *)src; + + for (i = c & 3; i--;) { + if (i & 1) { + *dst8++ = fb_readb(++src8); + } else { + *dst8++ = fb_readb(--src8); + src8 += 2; + } + } + src = (u32 __iomem *)src8; + } + + if (copy_to_user(buf, buffer, c)) { + err = -EFAULT; + break; + } + *ppos += c; + buf += c; + cnt += c; + count -= c; + } + + kfree(buffer); + + return (err) ? err : cnt; +} + +static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf, + size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + + u32 *buffer, *src; + u32 __iomem *dst; + int c, i, cnt = 0, err = 0; + unsigned long total_size; + + if (!info || !info->screen_base) + return -ENODEV; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + total_size = info->screen_size; + + if (total_size == 0) + total_size = info->fix.smem_len; + + if (p > total_size) + return -EFBIG; + + if (count > total_size) { + err = -EFBIG; + count = total_size; + } + + if (count + p > total_size) { + if (!err) + err = -ENOSPC; + + count = total_size - p; + } + + buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + dst = (u32 __iomem *)(info->screen_base + p); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + while (count) { + c = (count > PAGE_SIZE) ? PAGE_SIZE : count; + src = buffer; + + if (copy_from_user(src, buf, c)) { + err = -EFAULT; + break; + } + + for (i = c >> 2; i--;) { + fb_writel(big_swap(*src), dst++); + src++; + } + if (c & 3) { + u8 *src8 = (u8 *)src; + u8 __iomem *dst8 = (u8 __iomem *)dst; + + for (i = c & 3; i--;) { + if (i & 1) { + fb_writeb(*src8++, ++dst8); + } else { + fb_writeb(*src8++, --dst8); + dst8 += 2; + } + } + dst = (u32 __iomem *)dst8; + } + + *ppos += c; + buf += c; + cnt += c; + count -= c; + } + + kfree(buffer); + + return (cnt) ? cnt : err; +} + +static void sm7xx_set_timing(struct smtcfb_info *sfb) +{ + int i = 0, j = 0; + u32 m_nscreenstride; + + dev_dbg(&sfb->pdev->dev, + "sfb->width=%d sfb->height=%d sfb->fb->var.bits_per_pixel=%d sfb->hz=%d\n", + sfb->width, sfb->height, sfb->fb->var.bits_per_pixel, sfb->hz); + + for (j = 0; j < ARRAY_SIZE(vgamode); j++) { + if (vgamode[j].mmsizex != sfb->width || + vgamode[j].mmsizey != sfb->height || + vgamode[j].bpp != sfb->fb->var.bits_per_pixel || + vgamode[j].hz != sfb->hz) + continue; + + dev_dbg(&sfb->pdev->dev, + "vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n", + vgamode[j].mmsizex, vgamode[j].mmsizey, + vgamode[j].bpp, vgamode[j].hz); + + dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j); + + smtc_mmiowb(0x0, 0x3c6); + + smtc_seqw(0, 0x1); + + smtc_mmiowb(vgamode[j].init_misc, 0x3c2); + + /* init SEQ register SR00 - SR04 */ + for (i = 0; i < SIZE_SR00_SR04; i++) + smtc_seqw(i, vgamode[j].init_sr00_sr04[i]); + + /* init SEQ register SR10 - SR24 */ + for (i = 0; i < SIZE_SR10_SR24; i++) + smtc_seqw(i + 0x10, vgamode[j].init_sr10_sr24[i]); + + /* init SEQ register SR30 - SR75 */ + for (i = 0; i < SIZE_SR30_SR75; i++) + if ((i + 0x30) != 0x62 && (i + 0x30) != 0x6a && + (i + 0x30) != 0x6b) + smtc_seqw(i + 0x30, + vgamode[j].init_sr30_sr75[i]); + + /* init SEQ register SR80 - SR93 */ + for (i = 0; i < SIZE_SR80_SR93; i++) + smtc_seqw(i + 0x80, vgamode[j].init_sr80_sr93[i]); + + /* init SEQ register SRA0 - SRAF */ + for (i = 0; i < SIZE_SRA0_SRAF; i++) + smtc_seqw(i + 0xa0, vgamode[j].init_sra0_sraf[i]); + + /* init Graphic register GR00 - GR08 */ + for (i = 0; i < SIZE_GR00_GR08; i++) + smtc_grphw(i, vgamode[j].init_gr00_gr08[i]); + + /* init Attribute register AR00 - AR14 */ + for (i = 0; i < SIZE_AR00_AR14; i++) + smtc_attrw(i, vgamode[j].init_ar00_ar14[i]); + + /* init CRTC register CR00 - CR18 */ + for (i = 0; i < SIZE_CR00_CR18; i++) + smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]); + + /* init CRTC register CR30 - CR4D */ + for (i = 0; i < SIZE_CR30_CR4D; i++) + smtc_crtcw(i + 0x30, vgamode[j].init_cr30_cr4d[i]); + + /* init CRTC register CR90 - CRA7 */ + for (i = 0; i < SIZE_CR90_CRA7; i++) + smtc_crtcw(i + 0x90, vgamode[j].init_cr90_cra7[i]); + } + smtc_mmiowb(0x67, 0x3c2); + + /* set VPR registers */ + writel(0x0, sfb->vp_regs + 0x0C); + writel(0x0, sfb->vp_regs + 0x40); + + /* set data width */ + m_nscreenstride = (sfb->width * sfb->fb->var.bits_per_pixel) / 64; + switch (sfb->fb->var.bits_per_pixel) { + case 8: + writel(0x0, sfb->vp_regs + 0x0); + break; + case 16: + writel(0x00020000, sfb->vp_regs + 0x0); + break; + case 24: + writel(0x00040000, sfb->vp_regs + 0x0); + break; + case 32: + writel(0x00030000, sfb->vp_regs + 0x0); + break; + } + writel((u32)(((m_nscreenstride + 2) << 16) | m_nscreenstride), + sfb->vp_regs + 0x10); +} + +static void smtc_set_timing(struct smtcfb_info *sfb) +{ + switch (sfb->chip_id) { + case 0x710: + case 0x712: + case 0x720: + sm7xx_set_timing(sfb); + break; + } +} + +static void smtcfb_setmode(struct smtcfb_info *sfb) +{ + switch (sfb->fb->var.bits_per_pixel) { + case 32: + sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR; + sfb->fb->fix.line_length = sfb->fb->var.xres * 4; + sfb->fb->var.red.length = 8; + sfb->fb->var.green.length = 8; + sfb->fb->var.blue.length = 8; + sfb->fb->var.red.offset = 16; + sfb->fb->var.green.offset = 8; + sfb->fb->var.blue.offset = 0; + break; + case 24: + sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR; + sfb->fb->fix.line_length = sfb->fb->var.xres * 3; + sfb->fb->var.red.length = 8; + sfb->fb->var.green.length = 8; + sfb->fb->var.blue.length = 8; + sfb->fb->var.red.offset = 16; + sfb->fb->var.green.offset = 8; + sfb->fb->var.blue.offset = 0; + break; + case 8: + sfb->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; + sfb->fb->fix.line_length = sfb->fb->var.xres; + sfb->fb->var.red.length = 3; + sfb->fb->var.green.length = 3; + sfb->fb->var.blue.length = 2; + sfb->fb->var.red.offset = 5; + sfb->fb->var.green.offset = 2; + sfb->fb->var.blue.offset = 0; + break; + case 16: + default: + sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR; + sfb->fb->fix.line_length = sfb->fb->var.xres * 2; + sfb->fb->var.red.length = 5; + sfb->fb->var.green.length = 6; + sfb->fb->var.blue.length = 5; + sfb->fb->var.red.offset = 11; + sfb->fb->var.green.offset = 5; + sfb->fb->var.blue.offset = 0; + break; + } + + sfb->width = sfb->fb->var.xres; + sfb->height = sfb->fb->var.yres; + sfb->hz = 60; + smtc_set_timing(sfb); +} + +static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + /* sanity checks */ + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + + /* set valid default bpp */ + if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16) && + (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32)) + var->bits_per_pixel = 16; + + return 0; +} + +static int smtc_set_par(struct fb_info *info) +{ + smtcfb_setmode(info->par); + + return 0; +} + +static struct fb_ops smtcfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = smtc_check_var, + .fb_set_par = smtc_set_par, + .fb_setcolreg = smtc_setcolreg, + .fb_blank = smtc_blank, + .fb_fillrect = cfb_fillrect, + .fb_imageblit = cfb_imageblit, + .fb_copyarea = cfb_copyarea, + .fb_read = smtcfb_read, + .fb_write = smtcfb_write, +}; + +/* + * Unmap in the memory mapped IO registers + */ + +static void smtc_unmap_mmio(struct smtcfb_info *sfb) +{ + if (sfb && smtc_regbaseaddress) + smtc_regbaseaddress = NULL; +} + +/* + * Map in the screen memory + */ + +static int smtc_map_smem(struct smtcfb_info *sfb, + struct pci_dev *pdev, u_long smem_len) +{ + sfb->fb->fix.smem_start = pci_resource_start(pdev, 0); + + if (sfb->fb->var.bits_per_pixel == 32) + sfb->fb->fix.smem_start += big_addr; + + sfb->fb->fix.smem_len = smem_len; + + sfb->fb->screen_base = sfb->lfb; + + if (!sfb->fb->screen_base) { + dev_err(&pdev->dev, + "%s: unable to map screen memory\n", sfb->fb->fix.id); + return -ENOMEM; + } + + return 0; +} + +/* + * Unmap in the screen memory + * + */ +static void smtc_unmap_smem(struct smtcfb_info *sfb) +{ + if (sfb && sfb->fb->screen_base) { + iounmap(sfb->fb->screen_base); + sfb->fb->screen_base = NULL; + } +} + +/* + * We need to wake up the device and make sure its in linear memory mode. + */ +static inline void sm7xx_init_hw(void) +{ + outb_p(0x18, 0x3c4); + outb_p(0x11, 0x3c5); +} + +static int smtcfb_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct smtcfb_info *sfb; + struct fb_info *info; + u_long smem_size = 0x00800000; /* default 8MB */ + int err; + unsigned long mmio_base; + + dev_info(&pdev->dev, "Silicon Motion display driver.\n"); + + err = pci_enable_device(pdev); /* enable SMTC chip */ + if (err) + return err; + + err = pci_request_region(pdev, 0, "sm7xxfb"); + if (err < 0) { + dev_err(&pdev->dev, "cannot reserve framebuffer region\n"); + goto failed_regions; + } + + sprintf(smtcfb_fix.id, "sm%Xfb", ent->device); + + info = framebuffer_alloc(sizeof(*sfb), &pdev->dev); + if (!info) { + dev_err(&pdev->dev, "framebuffer_alloc failed\n"); + err = -ENOMEM; + goto failed_free; + } + + sfb = info->par; + sfb->fb = info; + sfb->chip_id = ent->device; + sfb->pdev = pdev; + info->flags = FBINFO_FLAG_DEFAULT; + info->fbops = &smtcfb_ops; + info->fix = smtcfb_fix; + info->var = smtcfb_var; + info->pseudo_palette = sfb->colreg; + info->par = sfb; + + pci_set_drvdata(pdev, sfb); + + sm7xx_init_hw(); + + /* get mode parameter from smtc_scr_info */ + if (smtc_scr_info.lfb_width != 0) { + sfb->fb->var.xres = smtc_scr_info.lfb_width; + sfb->fb->var.yres = smtc_scr_info.lfb_height; + sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth; + } else { + /* default resolution 1024x600 16bit mode */ + sfb->fb->var.xres = SCREEN_X_RES; + sfb->fb->var.yres = SCREEN_Y_RES; + sfb->fb->var.bits_per_pixel = SCREEN_BPP; + } + + big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth); + /* Map address and memory detection */ + mmio_base = pci_resource_start(pdev, 0); + pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id); + + switch (sfb->chip_id) { + case 0x710: + case 0x712: + sfb->fb->fix.mmio_start = mmio_base + 0x00400000; + sfb->fb->fix.mmio_len = 0x00400000; + smem_size = SM712_VIDEOMEMORYSIZE; + sfb->lfb = ioremap(mmio_base, mmio_addr); + if (!sfb->lfb) { + dev_err(&pdev->dev, + "%s: unable to map memory mapped IO!\n", + sfb->fb->fix.id); + err = -ENOMEM; + goto failed_fb; + } + + sfb->mmio = (smtc_regbaseaddress = + sfb->lfb + 0x00700000); + sfb->dp_regs = sfb->lfb + 0x00408000; + sfb->vp_regs = sfb->lfb + 0x0040c000; + if (sfb->fb->var.bits_per_pixel == 32) { + sfb->lfb += big_addr; + dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb); + } + + /* set MCLK = 14.31818 * (0x16 / 0x2) */ + smtc_seqw(0x6a, 0x16); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x62, 0x3e); + /* enable PCI burst */ + smtc_seqw(0x17, 0x20); + /* enable word swap */ + if (sfb->fb->var.bits_per_pixel == 32) + seqw17(); + break; + case 0x720: + sfb->fb->fix.mmio_start = mmio_base; + sfb->fb->fix.mmio_len = 0x00200000; + smem_size = SM722_VIDEOMEMORYSIZE; + sfb->dp_regs = ioremap(mmio_base, 0x00a00000); + sfb->lfb = sfb->dp_regs + 0x00200000; + sfb->mmio = (smtc_regbaseaddress = + sfb->dp_regs + 0x000c0000); + sfb->vp_regs = sfb->dp_regs + 0x800; + + smtc_seqw(0x62, 0xff); + smtc_seqw(0x6a, 0x0d); + smtc_seqw(0x6b, 0x02); + break; + default: + dev_err(&pdev->dev, + "No valid Silicon Motion display chip was detected!\n"); + + goto failed_fb; + } + + /* can support 32 bpp */ + if (15 == sfb->fb->var.bits_per_pixel) + sfb->fb->var.bits_per_pixel = 16; + + sfb->fb->var.xres_virtual = sfb->fb->var.xres; + sfb->fb->var.yres_virtual = sfb->fb->var.yres; + err = smtc_map_smem(sfb, pdev, smem_size); + if (err) + goto failed; + + smtcfb_setmode(sfb); + + err = register_framebuffer(info); + if (err < 0) + goto failed; + + dev_info(&pdev->dev, + "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.\n", + sfb->chip_id, sfb->chip_rev_id, sfb->fb->var.xres, + sfb->fb->var.yres, sfb->fb->var.bits_per_pixel); + + return 0; + +failed: + dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.\n"); + + smtc_unmap_smem(sfb); + smtc_unmap_mmio(sfb); +failed_fb: + framebuffer_release(info); + +failed_free: + pci_release_region(pdev, 0); + +failed_regions: + pci_disable_device(pdev); + + return err; +} + +/* + * 0x710 (LynxEM) + * 0x712 (LynxEM+) + * 0x720 (Lynx3DM, Lynx3DM+) + */ +static const struct pci_device_id smtcfb_pci_table[] = { + { PCI_DEVICE(0x126f, 0x710), }, + { PCI_DEVICE(0x126f, 0x712), }, + { PCI_DEVICE(0x126f, 0x720), }, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, smtcfb_pci_table); + +static void smtcfb_pci_remove(struct pci_dev *pdev) +{ + struct smtcfb_info *sfb; + + sfb = pci_get_drvdata(pdev); + smtc_unmap_smem(sfb); + smtc_unmap_mmio(sfb); + unregister_framebuffer(sfb->fb); + framebuffer_release(sfb->fb); + pci_release_region(pdev, 0); + pci_disable_device(pdev); +} + +#ifdef CONFIG_PM +static int smtcfb_pci_suspend(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct smtcfb_info *sfb; + + sfb = pci_get_drvdata(pdev); + + /* set the hw in sleep mode use external clock and self memory refresh + * so that we can turn off internal PLLs later on + */ + smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0)); + smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7)); + + console_lock(); + fb_set_suspend(sfb->fb, 1); + console_unlock(); + + /* additionally turn off all function blocks including internal PLLs */ + smtc_seqw(0x21, 0xff); + + return 0; +} + +static int smtcfb_pci_resume(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct smtcfb_info *sfb; + + sfb = pci_get_drvdata(pdev); + + /* reinit hardware */ + sm7xx_init_hw(); + switch (sfb->chip_id) { + case 0x710: + case 0x712: + /* set MCLK = 14.31818 * (0x16 / 0x2) */ + smtc_seqw(0x6a, 0x16); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x62, 0x3e); + /* enable PCI burst */ + smtc_seqw(0x17, 0x20); + if (sfb->fb->var.bits_per_pixel == 32) + seqw17(); + break; + case 0x720: + smtc_seqw(0x62, 0xff); + smtc_seqw(0x6a, 0x0d); + smtc_seqw(0x6b, 0x02); + break; + } + + smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0)); + smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb)); + + smtcfb_setmode(sfb); + + console_lock(); + fb_set_suspend(sfb->fb, 0); + console_unlock(); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume); +#define SM7XX_PM_OPS (&sm7xx_pm_ops) + +#else /* !CONFIG_PM */ + +#define SM7XX_PM_OPS NULL + +#endif /* !CONFIG_PM */ + +static struct pci_driver smtcfb_driver = { + .name = "smtcfb", + .id_table = smtcfb_pci_table, + .probe = smtcfb_pci_probe, + .remove = smtcfb_pci_remove, + .driver.pm = SM7XX_PM_OPS, +}; + +static int __init sm712fb_init(void) +{ + char *option = NULL; + + if (fb_get_options("sm712fb", &option)) + return -ENODEV; + if (option && *option) + mode_option = option; + sm7xx_vga_setup(mode_option); + + return pci_register_driver(&smtcfb_driver); +} + +module_init(sm712fb_init); + +static void __exit sm712fb_exit(void) +{ + pci_unregister_driver(&smtcfb_driver); +} + +module_exit(sm712fb_exit); + +MODULE_AUTHOR("Siliconmotion "); +MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c index 3e153c061..93f4c902d 100644 --- a/drivers/video/fbdev/ssd1307fb.c +++ b/drivers/video/fbdev/ssd1307fb.c @@ -656,8 +656,9 @@ static int ssd1307fb_probe(struct i2c_client *client, bl = backlight_device_register(bl_name, &client->dev, par, &ssd1307fb_bl_ops, NULL); if (IS_ERR(bl)) { - dev_err(&client->dev, "unable to register backlight device: %ld\n", - PTR_ERR(bl)); + ret = PTR_ERR(bl); + dev_err(&client->dev, "unable to register backlight device: %d\n", + ret); goto bl_init_error; } @@ -719,7 +720,6 @@ static struct i2c_driver ssd1307fb_driver = { .driver = { .name = "ssd1307fb", .of_match_table = ssd1307fb_of_match, - .owner = THIS_MODULE, }, }; diff --git a/drivers/video/fbdev/stifb.c b/drivers/video/fbdev/stifb.c index 735355b0e..7df4228e2 100644 --- a/drivers/video/fbdev/stifb.c +++ b/drivers/video/fbdev/stifb.c @@ -64,6 +64,7 @@ #include <linux/fb.h> #include <linux/init.h> #include <linux/ioport.h> +#include <linux/io.h> #include <asm/grfioctl.h> /* for HP-UX compatibility */ #include <asm/uaccess.h> diff --git a/drivers/video/fbdev/tridentfb.c b/drivers/video/fbdev/tridentfb.c index 7ed9a227f..01b43e9ce 100644 --- a/drivers/video/fbdev/tridentfb.c +++ b/drivers/video/fbdev/tridentfb.c @@ -226,7 +226,7 @@ static void blade_image_blit(struct tridentfb_par *par, const char *data, writemmr(par, DST1, point(x, y)); writemmr(par, DST2, point(x + w - 1, y + h - 1)); - memcpy(par->io_virt + 0x10000, data, 4 * size); + iowrite32_rep(par->io_virt + 0x10000, data, size); } static void blade_copy_rect(struct tridentfb_par *par, @@ -673,8 +673,14 @@ static int get_nativex(struct tridentfb_par *par) static inline void set_lwidth(struct tridentfb_par *par, int width) { write3X4(par, VGA_CRTC_OFFSET, width & 0xFF); - write3X4(par, AddColReg, - (read3X4(par, AddColReg) & 0xCF) | ((width & 0x300) >> 4)); + /* chips older than TGUI9660 have only 1 width bit in AddColReg */ + /* touching the other one breaks I2C/DDC */ + if (par->chip_id == TGUI9440 || par->chip_id == CYBER9320) + write3X4(par, AddColReg, + (read3X4(par, AddColReg) & 0xEF) | ((width & 0x100) >> 4)); + else + write3X4(par, AddColReg, + (read3X4(par, AddColReg) & 0xCF) | ((width & 0x300) >> 4)); } /* For resolutions smaller than FP resolution stretch */ diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index ff2b8731a..e9c2f7ba3 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -279,7 +279,7 @@ static int dlfb_set_video_mode(struct dlfb_data *dev, { char *buf; char *wrptr; - int retval = 0; + int retval; int writesize; struct urb *urb; @@ -1505,8 +1505,7 @@ static int dlfb_parse_vendor_descriptor(struct dlfb_data *dev, char *desc; char *buf; char *desc_end; - - int total_len = 0; + int total_len; buf = kzalloc(MAX_VENDOR_DESCRIPTOR_SIZE, GFP_KERNEL); if (!buf) @@ -1582,7 +1581,7 @@ static int dlfb_usb_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct usb_device *usbdev; - struct dlfb_data *dev = NULL; + struct dlfb_data *dev; int retval = -ENOMEM; /* usb initialization */ @@ -1665,7 +1664,6 @@ static void dlfb_init_framebuffer_work(struct work_struct *work) /* allocates framebuffer driver structure, not framebuffer memory */ info = framebuffer_alloc(0, dev->gdev); if (!info) { - retval = -ENOMEM; pr_err("framebuffer_alloc failed\n"); goto error; } @@ -1912,7 +1910,7 @@ static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size) static struct urb *dlfb_get_urb(struct dlfb_data *dev) { - int ret = 0; + int ret; struct list_head *entry; struct urb_node *unode; struct urb *urb = NULL; diff --git a/drivers/video/fbdev/vfb.c b/drivers/video/fbdev/vfb.c index 70a897b1e..b9c2f81fb 100644 --- a/drivers/video/fbdev/vfb.c +++ b/drivers/video/fbdev/vfb.c @@ -51,7 +51,14 @@ static void *rvmalloc(unsigned long size) if (!mem) return NULL; - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + /* + * VFB must clear memory to prevent kernel info + * leakage into userspace + * VGA-based drivers MUST NOT clear memory if + * they want to be able to take over vgacon + */ + + memset(mem, 0, size); adr = (unsigned long) mem; while (size > 0) { SetPageReserved(vmalloc_to_page((void *)adr)); @@ -490,14 +497,6 @@ static int vfb_probe(struct platform_device *dev) if (!(videomemory = rvmalloc(videomemorysize))) return retval; - /* - * VFB must clear memory to prevent kernel info - * leakage into userspace - * VGA-based drivers MUST NOT clear memory if - * they want to be able to take over vgacon - */ - memset(videomemory, 0, videomemorysize); - info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev); if (!info) goto err; diff --git a/drivers/video/fbdev/vt8623fb.c b/drivers/video/fbdev/vt8623fb.c index 8bac309c2..dd0f18e42 100644 --- a/drivers/video/fbdev/vt8623fb.c +++ b/drivers/video/fbdev/vt8623fb.c @@ -26,13 +26,9 @@ #include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */ #include <video/vga.h> -#ifdef CONFIG_MTRR -#include <asm/mtrr.h> -#endif - struct vt8623fb_info { char __iomem *mmio_base; - int mtrr_reg; + int wc_cookie; struct vgastate state; struct mutex open_lock; unsigned int ref_count; @@ -99,10 +95,7 @@ static struct svga_timing_regs vt8623_timing_regs = { /* Module parameters */ static char *mode_option = "640x480-8@60"; - -#ifdef CONFIG_MTRR static int mtrr = 1; -#endif MODULE_AUTHOR("(c) 2006 Ondrej Zajicek <santiago@crfreenet.org>"); MODULE_LICENSE("GPL"); @@ -112,11 +105,8 @@ module_param(mode_option, charp, 0644); MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)"); module_param_named(mode, mode_option, charp, 0); MODULE_PARM_DESC(mode, "Default video mode e.g. '648x480-8@60' (deprecated)"); - -#ifdef CONFIG_MTRR module_param(mtrr, int, 0444); MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)"); -#endif /* ------------------------------------------------------------------------- */ @@ -710,7 +700,7 @@ static int vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) info->fix.mmio_len = pci_resource_len(dev, 1); /* Map physical IO memory address into kernel space */ - info->screen_base = pci_iomap(dev, 0, 0); + info->screen_base = pci_iomap_wc(dev, 0, 0); if (! info->screen_base) { rc = -ENOMEM; dev_err(info->device, "iomap for framebuffer failed\n"); @@ -781,12 +771,9 @@ static int vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) /* Record a reference to the driver data */ pci_set_drvdata(dev, info); -#ifdef CONFIG_MTRR - if (mtrr) { - par->mtrr_reg = -1; - par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1); - } -#endif + if (mtrr) + par->wc_cookie = arch_phys_wc_add(info->fix.smem_start, + info->fix.smem_len); return 0; @@ -816,13 +803,7 @@ static void vt8623_pci_remove(struct pci_dev *dev) if (info) { struct vt8623fb_info *par = info->par; -#ifdef CONFIG_MTRR - if (par->mtrr_reg >= 0) { - mtrr_del(par->mtrr_reg, 0, 0); - par->mtrr_reg = -1; - } -#endif - + arch_phys_wc_del(par->wc_cookie); unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); diff --git a/drivers/video/fbdev/xen-fbfront.c b/drivers/video/fbdev/xen-fbfront.c index 09dc44736..0567d517e 100644 --- a/drivers/video/fbdev/xen-fbfront.c +++ b/drivers/video/fbdev/xen-fbfront.c @@ -46,7 +46,7 @@ struct xenfb_info { int nr_pages; int irq; struct xenfb_page *page; - unsigned long *mfns; + unsigned long *gfns; int update_wanted; /* XENFB_TYPE_UPDATE wanted */ int feature_resize; /* XENFB_TYPE_RESIZE ok */ struct xenfb_resize resize; /* protected by resize_lock */ @@ -402,8 +402,8 @@ static int xenfb_probe(struct xenbus_device *dev, info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT; - info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages); - if (!info->mfns) + info->gfns = vmalloc(sizeof(unsigned long) * info->nr_pages); + if (!info->gfns) goto error_nomem; /* set up shared page */ @@ -530,29 +530,29 @@ static int xenfb_remove(struct xenbus_device *dev) framebuffer_release(info->fb_info); } free_page((unsigned long)info->page); - vfree(info->mfns); + vfree(info->gfns); vfree(info->fb); kfree(info); return 0; } -static unsigned long vmalloc_to_mfn(void *address) +static unsigned long vmalloc_to_gfn(void *address) { - return pfn_to_mfn(vmalloc_to_pfn(address)); + return xen_page_to_gfn(vmalloc_to_page(address)); } static void xenfb_init_shared_page(struct xenfb_info *info, struct fb_info *fb_info) { int i; - int epd = PAGE_SIZE / sizeof(info->mfns[0]); + int epd = PAGE_SIZE / sizeof(info->gfns[0]); for (i = 0; i < info->nr_pages; i++) - info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); + info->gfns[i] = vmalloc_to_gfn(info->fb + i * PAGE_SIZE); for (i = 0; i * epd < info->nr_pages; i++) - info->page->pd[i] = vmalloc_to_mfn(&info->mfns[i * epd]); + info->page->pd[i] = vmalloc_to_gfn(&info->gfns[i * epd]); info->page->width = fb_info->var.xres; info->page->height = fb_info->var.yres; @@ -586,7 +586,7 @@ static int xenfb_connect_backend(struct xenbus_device *dev, goto unbind_irq; } ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", - virt_to_mfn(info->page)); + virt_to_gfn(info->page)); if (ret) goto error_xenbus; ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c index 32d8275e4..8a1076bee 100644 --- a/drivers/video/of_display_timing.c +++ b/drivers/video/of_display_timing.c @@ -210,6 +210,7 @@ struct display_timings *of_get_display_timings(struct device_node *np) */ pr_err("%s: error in timing %d\n", of_node_full_name(np), disp->num_timings + 1); + kfree(dt); goto timingfail; } |