diff options
Diffstat (limited to 'drivers/video')
| -rw-r--r-- | drivers/video/backlight/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/video/backlight/Makefile | 1 | ||||
| -rw-r--r-- | drivers/video/backlight/aw99706.c | 471 | ||||
| -rw-r--r-- | drivers/video/backlight/led_bl.c | 13 | ||||
| -rw-r--r-- | drivers/video/fbdev/aty/atyfb_base.c | 8 | ||||
| -rw-r--r-- | drivers/video/fbdev/core/bitblit.c | 16 | ||||
| -rw-r--r-- | drivers/video/fbdev/core/fbcon.c | 28 | ||||
| -rw-r--r-- | drivers/video/fbdev/core/fbmem.c | 1 | ||||
| -rw-r--r-- | drivers/video/fbdev/gbefb.c | 5 | ||||
| -rw-r--r-- | drivers/video/fbdev/gxt4500.c | 2 | ||||
| -rw-r--r-- | drivers/video/fbdev/i810/i810_main.c | 46 | ||||
| -rw-r--r-- | drivers/video/fbdev/pvr2fb.c | 2 | ||||
| -rw-r--r-- | drivers/video/fbdev/pxafb.c | 12 | ||||
| -rw-r--r-- | drivers/video/fbdev/ssd1307fb.c | 4 | ||||
| -rw-r--r-- | drivers/video/fbdev/tcx.c | 2 | ||||
| -rw-r--r-- | drivers/video/fbdev/tridentfb.c | 4 | ||||
| -rw-r--r-- | drivers/video/fbdev/valkyriefb.c | 2 | ||||
| -rw-r--r-- | drivers/video/fbdev/vesafb.c | 29 | ||||
| -rw-r--r-- | drivers/video/fbdev/vga16fb.c | 21 |
19 files changed, 613 insertions, 63 deletions
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index d9374d208cee..a1422ddd1c22 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -156,6 +156,14 @@ config BACKLIGHT_ATMEL_LCDC If in doubt, it's safe to enable this option; it doesn't kick in unless the board's description says it's wired that way. +config BACKLIGHT_AW99706 + tristate "Backlight Driver for Awinic AW99706" + depends on I2C + select REGMAP_I2C + help + If you have a LCD backlight connected to the WLED output of AW99706 + WLED output, say Y here to enable this driver. + config BACKLIGHT_EP93XX tristate "Cirrus EP93xx Backlight Driver" depends on FB_EP93XX @@ -185,6 +193,7 @@ config BACKLIGHT_KTD253 config BACKLIGHT_KTD2801 tristate "Backlight Driver for Kinetic KTD2801" + depends on GPIOLIB || COMPILE_TEST select LEDS_EXPRESSWIRE help Say Y to enable the backlight driver for the Kinetic KTD2801 1-wire diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index dfbb169bf6ea..a5d62b018102 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_BACKLIGHT_ADP8870) += adp8870_bl.o obj-$(CONFIG_BACKLIGHT_APPLE) += apple_bl.o obj-$(CONFIG_BACKLIGHT_APPLE_DWI) += apple_dwi_bl.o obj-$(CONFIG_BACKLIGHT_AS3711) += as3711_bl.o +obj-$(CONFIG_BACKLIGHT_AW99706) += aw99706.o obj-$(CONFIG_BACKLIGHT_BD6107) += bd6107.o obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o diff --git a/drivers/video/backlight/aw99706.c b/drivers/video/backlight/aw99706.c new file mode 100644 index 000000000000..df5b23b2f753 --- /dev/null +++ b/drivers/video/backlight/aw99706.c @@ -0,0 +1,471 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * aw99706 - Backlight driver for the AWINIC AW99706 + * + * Copyright (C) 2025 Junjie Cao <caojunjie650@gmail.com> + * Copyright (C) 2025 Pengyu Luo <mitltlatltl@gmail.com> + * + * Based on vendor driver: + * Copyright (c) 2023 AWINIC Technology CO., LTD + */ + +#include <linux/backlight.h> +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/regmap.h> + +#define AW99706_MAX_BRT_LVL 4095 +#define AW99706_REG_MAX 0x1F +#define AW99706_ID 0x07 + +/* registers list */ +#define AW99706_CFG0_REG 0x00 +#define AW99706_DIM_MODE_MASK GENMASK(1, 0) + +#define AW99706_CFG1_REG 0x01 +#define AW99706_SW_FREQ_MASK GENMASK(3, 0) +#define AW99706_SW_ILMT_MASK GENMASK(5, 4) + +#define AW99706_CFG2_REG 0x02 +#define AW99706_ILED_MAX_MASK GENMASK(6, 0) +#define AW99706_UVLOSEL_MASK BIT(7) + +#define AW99706_CFG3_REG 0x03 +#define AW99706_CFG4_REG 0x04 +#define AW99706_BRT_MSB_MASK GENMASK(3, 0) + +#define AW99706_CFG5_REG 0x05 +#define AW99706_BRT_LSB_MASK GENMASK(7, 0) + +#define AW99706_CFG6_REG 0x06 +#define AW99706_RAMP_CTL_MASK GENMASK(7, 6) + +#define AW99706_CFG7_REG 0x07 +#define AW99706_CFG8_REG 0x08 +#define AW99706_CFG9_REG 0x09 +#define AW99706_CFGA_REG 0x0A +#define AW99706_CFGB_REG 0x0B +#define AW99706_CFGC_REG 0x0C +#define AW99706_CFGD_REG 0x0D +#define AW99706_FLAG_REG 0x10 +#define AW99706_BACKLIGHT_EN_MASK BIT(7) + +#define AW99706_CHIPID_REG 0x11 +#define AW99706_LED_OPEN_FLAG_REG 0x12 +#define AW99706_LED_SHORT_FLAG_REG 0x13 +#define AW99706_MTPLDOSEL_REG 0x1E +#define AW99706_MTPRUN_REG 0x1F + +#define RESV 0 + +/* Boost switching frequency table, in Hz */ +static const u32 aw99706_sw_freq_tbl[] = { + RESV, RESV, RESV, RESV, 300000, 400000, 500000, 600000, + 660000, 750000, 850000, 1000000, 1200000, 1330000, 1500000, 1700000 +}; + +/* Switching current limitation table, in uA */ +static const u32 aw99706_sw_ilmt_tbl[] = { + 1500000, 2000000, 2500000, 3000000 +}; + +/* ULVO threshold table, in uV */ +static const u32 aw99706_ulvo_thres_tbl[] = { + 2200000, 5000000 +}; + +struct aw99706_dt_prop { + const char * const name; + int (*lookup)(const struct aw99706_dt_prop *prop, u32 dt_val, u8 *val); + const u32 * const lookup_tbl; + u8 tbl_size; + u8 reg; + u8 mask; + u32 def_val; +}; + +static int aw99706_dt_property_lookup(const struct aw99706_dt_prop *prop, + u32 dt_val, u8 *val) +{ + int i; + + if (!prop->lookup_tbl) { + *val = dt_val; + return 0; + } + + for (i = 0; i < prop->tbl_size; i++) + if (prop->lookup_tbl[i] == dt_val) + break; + + *val = i; + + return i == prop->tbl_size ? -1 : 0; +} + +#define MIN_ILED_MAX 5000 +#define MAX_ILED_MAX 50000 +#define STEP_ILED_MAX 500 + +static int +aw99706_dt_property_iled_max_convert(const struct aw99706_dt_prop *prop, + u32 dt_val, u8 *val) +{ + if (dt_val > MAX_ILED_MAX || dt_val < MIN_ILED_MAX) + return -1; + + *val = (dt_val - MIN_ILED_MAX) / STEP_ILED_MAX; + + return (dt_val - MIN_ILED_MAX) % STEP_ILED_MAX; +} + +static const struct aw99706_dt_prop aw99706_dt_props[] = { + { + "awinic,dim-mode", aw99706_dt_property_lookup, + NULL, 0, + AW99706_CFG0_REG, AW99706_DIM_MODE_MASK, 1, + }, + { + "awinic,sw-freq", aw99706_dt_property_lookup, + aw99706_sw_freq_tbl, ARRAY_SIZE(aw99706_sw_freq_tbl), + AW99706_CFG1_REG, AW99706_SW_FREQ_MASK, 750000, + }, + { + "awinic,sw-ilmt", aw99706_dt_property_lookup, + aw99706_sw_ilmt_tbl, ARRAY_SIZE(aw99706_sw_ilmt_tbl), + AW99706_CFG1_REG, AW99706_SW_ILMT_MASK, 3000000, + }, + { + "awinic,iled-max", aw99706_dt_property_iled_max_convert, + NULL, 0, + AW99706_CFG2_REG, AW99706_ILED_MAX_MASK, 20000, + + }, + { + "awinic,uvlo-thres", aw99706_dt_property_lookup, + aw99706_ulvo_thres_tbl, ARRAY_SIZE(aw99706_ulvo_thres_tbl), + AW99706_CFG2_REG, AW99706_UVLOSEL_MASK, 2200000, + }, + { + "awinic,ramp-ctl", aw99706_dt_property_lookup, + NULL, 0, + AW99706_CFG6_REG, AW99706_RAMP_CTL_MASK, 2, + } +}; + +struct reg_init_data { + u8 reg; + u8 mask; + u8 val; +}; + +struct aw99706_device { + struct i2c_client *client; + struct device *dev; + struct regmap *regmap; + struct backlight_device *bl_dev; + struct gpio_desc *hwen_gpio; + struct reg_init_data init_tbl[ARRAY_SIZE(aw99706_dt_props)]; + bool bl_enable; +}; + +enum reg_access { + REG_NONE_ACCESS = 0, + REG_RD_ACCESS = 1, + REG_WR_ACCESS = 2, +}; + +static const u8 aw99706_regs[AW99706_REG_MAX + 1] = { + [AW99706_CFG0_REG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW99706_CFG1_REG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW99706_CFG2_REG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW99706_CFG3_REG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW99706_CFG4_REG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW99706_CFG5_REG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW99706_CFG6_REG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW99706_CFG7_REG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW99706_CFG8_REG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW99706_CFG9_REG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW99706_CFGA_REG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW99706_CFGB_REG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW99706_CFGC_REG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW99706_CFGD_REG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW99706_FLAG_REG] = REG_RD_ACCESS, + [AW99706_CHIPID_REG] = REG_RD_ACCESS, + [AW99706_LED_OPEN_FLAG_REG] = REG_RD_ACCESS, + [AW99706_LED_SHORT_FLAG_REG] = REG_RD_ACCESS, + + /* + * Write bit is dropped here, writing BIT(0) to MTPLDOSEL will unlock + * Multi-time Programmable (MTP). + */ + [AW99706_MTPLDOSEL_REG] = REG_RD_ACCESS, + [AW99706_MTPRUN_REG] = REG_NONE_ACCESS, +}; + +static bool aw99706_readable_reg(struct device *dev, unsigned int reg) +{ + return aw99706_regs[reg] & REG_RD_ACCESS; +} + +static bool aw99706_writeable_reg(struct device *dev, unsigned int reg) +{ + return aw99706_regs[reg] & REG_WR_ACCESS; +} + +static inline int aw99706_i2c_read(struct aw99706_device *aw, u8 reg, + unsigned int *val) +{ + return regmap_read(aw->regmap, reg, val); +} + +static inline int aw99706_i2c_write(struct aw99706_device *aw, u8 reg, u8 val) +{ + return regmap_write(aw->regmap, reg, val); +} + +static inline int aw99706_i2c_update_bits(struct aw99706_device *aw, u8 reg, + u8 mask, u8 val) +{ + return regmap_update_bits(aw->regmap, reg, mask, val); +} + +static void aw99706_dt_parse(struct aw99706_device *aw, + struct backlight_properties *bl_props) +{ + const struct aw99706_dt_prop *prop; + u32 dt_val; + int ret, i; + u8 val; + + for (i = 0; i < ARRAY_SIZE(aw99706_dt_props); i++) { + prop = &aw99706_dt_props[i]; + ret = device_property_read_u32(aw->dev, prop->name, &dt_val); + if (ret < 0) + dt_val = prop->def_val; + + if (prop->lookup(prop, dt_val, &val)) { + dev_warn(aw->dev, "invalid value %d for property %s, using default value %d\n", + dt_val, prop->name, prop->def_val); + + prop->lookup(prop, prop->def_val, &val); + } + + aw->init_tbl[i].reg = prop->reg; + aw->init_tbl[i].mask = prop->mask; + aw->init_tbl[i].val = val << __ffs(prop->mask); + } + + bl_props->brightness = AW99706_MAX_BRT_LVL >> 1; + bl_props->max_brightness = AW99706_MAX_BRT_LVL; + device_property_read_u32(aw->dev, "default-brightness", + &bl_props->brightness); + device_property_read_u32(aw->dev, "max-brightness", + &bl_props->max_brightness); + + if (bl_props->max_brightness > AW99706_MAX_BRT_LVL) + bl_props->max_brightness = AW99706_MAX_BRT_LVL; + + if (bl_props->brightness > bl_props->max_brightness) + bl_props->brightness = bl_props->max_brightness; +} + +static int aw99706_hw_init(struct aw99706_device *aw) +{ + int ret, i; + + gpiod_set_value_cansleep(aw->hwen_gpio, 1); + + for (i = 0; i < ARRAY_SIZE(aw->init_tbl); i++) { + ret = aw99706_i2c_update_bits(aw, aw->init_tbl[i].reg, + aw->init_tbl[i].mask, + aw->init_tbl[i].val); + if (ret < 0) { + dev_err(aw->dev, "Failed to write init data %d\n", ret); + return ret; + } + } + + return 0; +} + +static int aw99706_bl_enable(struct aw99706_device *aw, bool en) +{ + int ret; + u8 val; + + val = FIELD_PREP(AW99706_BACKLIGHT_EN_MASK, en); + ret = aw99706_i2c_update_bits(aw, AW99706_CFGD_REG, + AW99706_BACKLIGHT_EN_MASK, val); + if (ret) + dev_err(aw->dev, "Failed to enable backlight!\n"); + + return ret; +} + +static int aw99706_update_brightness(struct aw99706_device *aw, u32 brt_lvl) +{ + bool bl_enable_now = !!brt_lvl; + int ret; + + ret = aw99706_i2c_write(aw, AW99706_CFG4_REG, + (brt_lvl >> 8) & AW99706_BRT_MSB_MASK); + if (ret < 0) + return ret; + + ret = aw99706_i2c_write(aw, AW99706_CFG5_REG, + brt_lvl & AW99706_BRT_LSB_MASK); + if (ret < 0) + return ret; + + if (aw->bl_enable != bl_enable_now) { + ret = aw99706_bl_enable(aw, bl_enable_now); + if (!ret) + aw->bl_enable = bl_enable_now; + } + + return ret; +} + +static int aw99706_bl_update_status(struct backlight_device *bl) +{ + struct aw99706_device *aw = bl_get_data(bl); + + return aw99706_update_brightness(aw, bl->props.brightness); +} + +static const struct backlight_ops aw99706_bl_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = aw99706_bl_update_status, +}; + +static const struct regmap_config aw99706_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = AW99706_REG_MAX, + .writeable_reg = aw99706_writeable_reg, + .readable_reg = aw99706_readable_reg, +}; + +static int aw99706_chip_id_read(struct aw99706_device *aw) +{ + int ret; + unsigned int val; + + ret = aw99706_i2c_read(aw, AW99706_CHIPID_REG, &val); + if (ret < 0) + return ret; + + return val; +} + +static int aw99706_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct aw99706_device *aw; + struct backlight_device *bl_dev; + struct backlight_properties props = {}; + int ret = 0; + + aw = devm_kzalloc(dev, sizeof(*aw), GFP_KERNEL); + if (!aw) + return -ENOMEM; + + aw->client = client; + aw->dev = dev; + i2c_set_clientdata(client, aw); + + aw->regmap = devm_regmap_init_i2c(client, &aw99706_regmap_config); + if (IS_ERR(aw->regmap)) + return dev_err_probe(dev, PTR_ERR(aw->regmap), + "Failed to init regmap\n"); + + ret = aw99706_chip_id_read(aw); + if (ret != AW99706_ID) + return dev_err_probe(dev, -ENODEV, + "Unknown chip id 0x%02x\n", ret); + + aw99706_dt_parse(aw, &props); + + aw->hwen_gpio = devm_gpiod_get(aw->dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(aw->hwen_gpio)) + return dev_err_probe(dev, PTR_ERR(aw->hwen_gpio), + "Failed to get enable gpio\n"); + + ret = aw99706_hw_init(aw); + if (ret < 0) + return dev_err_probe(dev, ret, + "Failed to initialize the chip\n"); + + props.type = BACKLIGHT_RAW; + props.scale = BACKLIGHT_SCALE_LINEAR; + + bl_dev = devm_backlight_device_register(dev, "aw99706-backlight", dev, + aw, &aw99706_bl_ops, &props); + if (IS_ERR(bl_dev)) + return dev_err_probe(dev, PTR_ERR(bl_dev), + "Failed to register backlight!\n"); + + aw->bl_dev = bl_dev; + + return 0; +} + +static void aw99706_remove(struct i2c_client *client) +{ + struct aw99706_device *aw = i2c_get_clientdata(client); + + aw99706_update_brightness(aw, 0); + + msleep(50); + + gpiod_set_value_cansleep(aw->hwen_gpio, 0); +} + +static int aw99706_suspend(struct device *dev) +{ + struct aw99706_device *aw = dev_get_drvdata(dev); + + return aw99706_update_brightness(aw, 0); +} + +static int aw99706_resume(struct device *dev) +{ + struct aw99706_device *aw = dev_get_drvdata(dev); + + return aw99706_hw_init(aw); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(aw99706_pm_ops, aw99706_suspend, aw99706_resume); + +static const struct i2c_device_id aw99706_ids[] = { + { "aw99706" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aw99706_ids); + +static const struct of_device_id aw99706_match_table[] = { + { .compatible = "awinic,aw99706", }, + { } +}; +MODULE_DEVICE_TABLE(of, aw99706_match_table); + +static struct i2c_driver aw99706_i2c_driver = { + .probe = aw99706_probe, + .remove = aw99706_remove, + .id_table = aw99706_ids, + .driver = { + .name = "aw99706", + .of_match_table = aw99706_match_table, + .pm = pm_ptr(&aw99706_pm_ops), + }, +}; + +module_i2c_driver(aw99706_i2c_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("BackLight driver for aw99706"); diff --git a/drivers/video/backlight/led_bl.c b/drivers/video/backlight/led_bl.c index efc5e380669a..f7ab9b360731 100644 --- a/drivers/video/backlight/led_bl.c +++ b/drivers/video/backlight/led_bl.c @@ -211,6 +211,19 @@ static int led_bl_probe(struct platform_device *pdev) } for (i = 0; i < priv->nb_leds; i++) { + struct device_link *link; + + link = device_link_add(&pdev->dev, priv->leds[i]->dev->parent, + DL_FLAG_AUTOREMOVE_CONSUMER); + if (!link) { + dev_err(&pdev->dev, "Failed to add devlink (consumer %s, supplier %s)\n", + dev_name(&pdev->dev), dev_name(priv->leds[i]->dev->parent)); + backlight_device_unregister(priv->bl_dev); + return -EINVAL; + } + } + + for (i = 0; i < priv->nb_leds; i++) { mutex_lock(&priv->leds[i]->led_access); led_sysfs_disable(priv->leds[i]); mutex_unlock(&priv->leds[i]->led_access); diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c index 210fd3ac18a4..56ef1d88e003 100644 --- a/drivers/video/fbdev/aty/atyfb_base.c +++ b/drivers/video/fbdev/aty/atyfb_base.c @@ -2614,8 +2614,12 @@ static int aty_init(struct fb_info *info) pr_cont("\n"); } #endif - if (par->pll_ops->init_pll) - par->pll_ops->init_pll(info, &par->pll); + if (par->pll_ops->init_pll) { + ret = par->pll_ops->init_pll(info, &par->pll); + if (ret) + return ret; + } + if (par->pll_ops->resume_pll) par->pll_ops->resume_pll(info, &par->pll); diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c index 9d2e59796c3e..085ffb44c51a 100644 --- a/drivers/video/fbdev/core/bitblit.c +++ b/drivers/video/fbdev/core/bitblit.c @@ -79,12 +79,16 @@ static inline void bit_putcs_aligned(struct vc_data *vc, struct fb_info *info, struct fb_image *image, u8 *buf, u8 *dst) { u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + unsigned int charcnt = vc->vc_font.charcount; u32 idx = vc->vc_font.width >> 3; u8 *src; while (cnt--) { - src = vc->vc_font.data + (scr_readw(s++)& - charmask)*cellsize; + u16 ch = scr_readw(s++) & charmask; + + if (ch >= charcnt) + ch = 0; + src = vc->vc_font.data + (unsigned int)ch * cellsize; if (attr) { update_attr(buf, src, attr, vc); @@ -112,14 +116,18 @@ static inline void bit_putcs_unaligned(struct vc_data *vc, u8 *dst) { u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff; + unsigned int charcnt = vc->vc_font.charcount; u32 shift_low = 0, mod = vc->vc_font.width % 8; u32 shift_high = 8; u32 idx = vc->vc_font.width >> 3; u8 *src; while (cnt--) { - src = vc->vc_font.data + (scr_readw(s++)& - charmask)*cellsize; + u16 ch = scr_readw(s++) & charmask; + + if (ch >= charcnt) + ch = 0; + src = vc->vc_font.data + (unsigned int)ch * cellsize; if (attr) { update_attr(buf, src, attr, vc); diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index e2e69aab6680..34ea14412ace 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -66,6 +66,7 @@ #include <linux/string.h> #include <linux/kd.h> #include <linux/panic.h> +#include <linux/pci.h> #include <linux/printk.h> #include <linux/slab.h> #include <linux/fb.h> @@ -78,6 +79,7 @@ #include <linux/interrupt.h> #include <linux/crc32.h> /* For counting font checksums */ #include <linux/uaccess.h> +#include <linux/vga_switcheroo.h> #include <asm/irq.h> #include "fbcon.h" @@ -2802,6 +2804,25 @@ int fbcon_mode_deleted(struct fb_info *info, return found; } +static void fbcon_delete_mode(struct fb_videomode *m) +{ + struct fbcon_display *p; + + for (int i = first_fb_vc; i <= last_fb_vc; i++) { + p = &fb_display[i]; + if (p->mode == m) + p->mode = NULL; + } +} + +void fbcon_delete_modelist(struct list_head *head) +{ + struct fb_modelist *modelist; + + list_for_each_entry(modelist, head, list) + fbcon_delete_mode(&modelist->mode); +} + #ifdef CONFIG_VT_HW_CONSOLE_BINDING static void fbcon_unbind(void) { @@ -2872,6 +2893,9 @@ void fbcon_fb_unregistered(struct fb_info *info) console_lock(); + if (info->device && dev_is_pci(info->device)) + vga_switcheroo_client_fb_set(to_pci_dev(info->device), NULL); + fbcon_registered_fb[info->node] = NULL; fbcon_num_registered_fb--; @@ -3005,6 +3029,10 @@ static int do_fb_registered(struct fb_info *info) } } + /* Set the fb info for vga_switcheroo clients. Does nothing otherwise. */ + if (info->device && dev_is_pci(info->device)) + vga_switcheroo_client_fb_set(to_pci_dev(info->device), info); + return ret; } diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 53f1719b1ae1..eff757ebbed1 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -544,6 +544,7 @@ static void do_unregister_framebuffer(struct fb_info *fb_info) fb_info->pixmap.addr = NULL; } + fbcon_delete_modelist(&fb_info->modelist); fb_destroy_modelist(&fb_info->modelist); registered_fb[fb_info->node] = NULL; num_registered_fb--; diff --git a/drivers/video/fbdev/gbefb.c b/drivers/video/fbdev/gbefb.c index 4c36a3e409be..cb6ff15a21db 100644 --- a/drivers/video/fbdev/gbefb.c +++ b/drivers/video/fbdev/gbefb.c @@ -12,6 +12,7 @@ #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/dma-direct.h> #include <linux/errno.h> #include <linux/gfp.h> #include <linux/fb.h> @@ -65,7 +66,7 @@ struct gbefb_par { static unsigned int gbe_mem_size = CONFIG_FB_GBE_MEM * 1024*1024; static void *gbe_mem; static dma_addr_t gbe_dma_addr; -static unsigned long gbe_mem_phys; +static phys_addr_t gbe_mem_phys; static struct { uint16_t *cpu; @@ -1183,7 +1184,7 @@ static int gbefb_probe(struct platform_device *p_dev) goto out_release_mem_region; } - gbe_mem_phys = (unsigned long) gbe_dma_addr; + gbe_mem_phys = dma_to_phys(&p_dev->dev, gbe_dma_addr); } par = info->par; diff --git a/drivers/video/fbdev/gxt4500.c b/drivers/video/fbdev/gxt4500.c index 15a82c6b609e..1ee0a1efa18e 100644 --- a/drivers/video/fbdev/gxt4500.c +++ b/drivers/video/fbdev/gxt4500.c @@ -704,7 +704,7 @@ static int gxt4500_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } info->var = var; if (gxt4500_set_par(info)) { - printk(KERN_ERR "gxt4500: cannot set video mode\n"); + dev_err(&pdev->dev, "cannot set video mode\n"); goto err_free_cmap; } diff --git a/drivers/video/fbdev/i810/i810_main.c b/drivers/video/fbdev/i810/i810_main.c index d73a795fe1be..10b914a24114 100644 --- a/drivers/video/fbdev/i810/i810_main.c +++ b/drivers/video/fbdev/i810/i810_main.c @@ -1012,7 +1012,7 @@ static int i810_check_params(struct fb_var_screeninfo *var, var->bits_per_pixel); vidmem = line_length * info->var.yres; if (vxres < var->xres) { - printk("i810fb: required video memory, " + dev_info(&par->dev->dev, "required video memory, " "%d bytes, for %dx%d-%d (virtual) " "is out of range\n", vidmem, vxres, vyres, @@ -1067,9 +1067,9 @@ static int i810_check_params(struct fb_var_screeninfo *var, |(info->monspecs.hfmax-HFMAX) |(info->monspecs.vfmin-VFMIN) |(info->monspecs.vfmax-VFMAX); - printk("i810fb: invalid video mode%s\n", - default_sync ? "" : ". Specifying " - "vsyncN/hsyncN parameters may help"); + dev_err(&par->dev->dev, "invalid video mode%s\n", + default_sync ? "" : ". Specifying " + "vsyncN/hsyncN parameters may help"); retval = -EINVAL; } } @@ -1674,19 +1674,19 @@ static int i810_alloc_agp_mem(struct fb_info *info) size = par->fb.size + par->iring.size; if (!(bridge = agp_backend_acquire(par->dev))) { - printk("i810fb_alloc_fbmem: cannot acquire agpgart\n"); + dev_warn(&par->dev->dev, "cannot acquire agpgart\n"); return -ENODEV; } if (!(par->i810_gtt.i810_fb_memory = agp_allocate_memory(bridge, size >> 12, AGP_NORMAL_MEMORY))) { - printk("i810fb_alloc_fbmem: can't allocate framebuffer " + dev_warn(&par->dev->dev, "can't allocate framebuffer " "memory\n"); agp_backend_release(bridge); return -ENOMEM; } if (agp_bind_memory(par->i810_gtt.i810_fb_memory, par->fb.offset)) { - printk("i810fb_alloc_fbmem: can't bind framebuffer memory\n"); + dev_warn(&par->dev->dev, "can't bind framebuffer memory\n"); agp_backend_release(bridge); return -EBUSY; } @@ -1694,14 +1694,14 @@ static int i810_alloc_agp_mem(struct fb_info *info) if (!(par->i810_gtt.i810_cursor_memory = agp_allocate_memory(bridge, par->cursor_heap.size >> 12, AGP_PHYSICAL_MEMORY))) { - printk("i810fb_alloc_cursormem: can't allocate " + dev_warn(&par->dev->dev, "can't allocate " "cursor memory\n"); agp_backend_release(bridge); return -ENOMEM; } if (agp_bind_memory(par->i810_gtt.i810_cursor_memory, par->cursor_heap.offset)) { - printk("i810fb_alloc_cursormem: cannot bind cursor memory\n"); + dev_warn(&par->dev->dev, "cannot bind cursor memory\n"); agp_backend_release(bridge); return -EBUSY; } @@ -1844,7 +1844,7 @@ static int i810_allocate_pci_resource(struct i810fb_par *par, int err; if ((err = pci_enable_device(par->dev))) { - printk("i810fb_init: cannot enable device\n"); + dev_err(&par->dev->dev, "cannot enable device\n"); return err; } par->res_flags |= PCI_DEVICE_ENABLED; @@ -1859,14 +1859,14 @@ static int i810_allocate_pci_resource(struct i810fb_par *par, par->mmio_start_phys = pci_resource_start(par->dev, 0); } if (!par->aperture.size) { - printk("i810fb_init: device is disabled\n"); + dev_warn(&par->dev->dev, "device is disabled\n"); return -ENOMEM; } if (!request_mem_region(par->aperture.physical, par->aperture.size, i810_pci_list[entry->driver_data])) { - printk("i810fb_init: cannot request framebuffer region\n"); + dev_warn(&par->dev->dev, "cannot request framebuffer region\n"); return -ENODEV; } par->res_flags |= FRAMEBUFFER_REQ; @@ -1874,14 +1874,14 @@ static int i810_allocate_pci_resource(struct i810fb_par *par, par->aperture.virtual = ioremap_wc(par->aperture.physical, par->aperture.size); if (!par->aperture.virtual) { - printk("i810fb_init: cannot remap framebuffer region\n"); + dev_warn(&par->dev->dev, "cannot remap framebuffer region\n"); return -ENODEV; } if (!request_mem_region(par->mmio_start_phys, MMIO_SIZE, i810_pci_list[entry->driver_data])) { - printk("i810fb_init: cannot request mmio region\n"); + dev_warn(&par->dev->dev, "cannot request mmio region\n"); return -ENODEV; } par->res_flags |= MMIO_REQ; @@ -1889,7 +1889,7 @@ static int i810_allocate_pci_resource(struct i810fb_par *par, par->mmio_start_virtual = ioremap(par->mmio_start_phys, MMIO_SIZE); if (!par->mmio_start_virtual) { - printk("i810fb_init: cannot remap mmio region\n"); + dev_warn(&par->dev->dev, "cannot remap mmio region\n"); return -ENODEV; } @@ -1921,12 +1921,12 @@ static void i810fb_find_init_mode(struct fb_info *info) } if (!err) - printk("i810fb_init_pci: DDC probe successful\n"); + dev_info(&par->dev->dev, "DDC probe successful\n"); fb_edid_to_monspecs(par->edid, specs); if (specs->modedb == NULL) - printk("i810fb_init_pci: Unable to get Mode Database\n"); + dev_info(&par->dev->dev, "Unable to get Mode Database\n"); fb_videomode_to_modelist(specs->modedb, specs->modedb_len, &info->modelist); @@ -2072,7 +2072,7 @@ static int i810fb_init_pci(struct pci_dev *dev, if (err < 0) { i810fb_release_resource(info, par); - printk("i810fb_init: cannot register framebuffer device\n"); + dev_warn(&par->dev->dev, "cannot register framebuffer device\n"); return err; } @@ -2084,10 +2084,10 @@ static int i810fb_init_pci(struct pci_dev *dev, vfreq = hfreq/(info->var.yres + info->var.upper_margin + info->var.vsync_len + info->var.lower_margin); - printk("I810FB: fb%d : %s v%d.%d.%d%s\n" - "I810FB: Video RAM : %dK\n" - "I810FB: Monitor : H: %d-%d KHz V: %d-%d Hz\n" - "I810FB: Mode : %dx%d-%dbpp@%dHz\n", + dev_info(&par->dev->dev, "fb%d : %s v%d.%d.%d%s\n" + "Video RAM : %dK\n" + "Monitor : H: %d-%d KHz V: %d-%d Hz\n" + "Mode : %dx%d-%dbpp@%dHz\n", info->node, i810_pci_list[entry->driver_data], VERSION_MAJOR, VERSION_MINOR, VERSION_TEENIE, BRANCH_VERSION, @@ -2137,7 +2137,7 @@ static void i810fb_remove_pci(struct pci_dev *dev) unregister_framebuffer(info); i810fb_release_resource(info, par); - printk("cleanup_module: unloaded i810 framebuffer device\n"); + dev_info(&par->dev->dev, "unloaded i810 framebuffer device\n"); } #ifndef MODULE diff --git a/drivers/video/fbdev/pvr2fb.c b/drivers/video/fbdev/pvr2fb.c index cbdb1caf61bd..0b8d23c12b77 100644 --- a/drivers/video/fbdev/pvr2fb.c +++ b/drivers/video/fbdev/pvr2fb.c @@ -192,7 +192,7 @@ static unsigned long pvr2fb_map; #ifdef CONFIG_PVR2_DMA static unsigned int shdma = PVR2_CASCADE_CHAN; -static unsigned int pvr2dma = ONCHIP_NR_DMA_CHANNELS; +static unsigned int pvr2dma = CONFIG_NR_ONCHIP_DMA_CHANNELS; #endif static struct fb_videomode pvr2_modedb[] = { diff --git a/drivers/video/fbdev/pxafb.c b/drivers/video/fbdev/pxafb.c index b96a8a96bce8..e418eee825fb 100644 --- a/drivers/video/fbdev/pxafb.c +++ b/drivers/video/fbdev/pxafb.c @@ -419,12 +419,12 @@ static int pxafb_adjust_timing(struct pxafb_info *fbi, var->yres = max_t(int, var->yres, MIN_YRES); if (!(fbi->lccr0 & LCCR0_LCDT)) { - clamp_val(var->hsync_len, 1, 64); - clamp_val(var->vsync_len, 1, 64); - clamp_val(var->left_margin, 1, 255); - clamp_val(var->right_margin, 1, 255); - clamp_val(var->upper_margin, 1, 255); - clamp_val(var->lower_margin, 1, 255); + var->hsync_len = clamp(var->hsync_len, 1, 64); + var->vsync_len = clamp(var->vsync_len, 1, 64); + var->left_margin = clamp(var->left_margin, 1, 255); + var->right_margin = clamp(var->right_margin, 1, 255); + var->upper_margin = clamp(var->upper_margin, 1, 255); + var->lower_margin = clamp(var->lower_margin, 1, 255); } /* make sure each line is aligned on word boundary */ diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c index aa6cc0a8151a..83dd31fa1fab 100644 --- a/drivers/video/fbdev/ssd1307fb.c +++ b/drivers/video/fbdev/ssd1307fb.c @@ -680,7 +680,7 @@ static int ssd1307fb_probe(struct i2c_client *client) if (!ssd1307fb_defio) { dev_err(dev, "Couldn't allocate deferred io.\n"); ret = -ENOMEM; - goto fb_alloc_error; + goto fb_defio_error; } ssd1307fb_defio->delay = HZ / refreshrate; @@ -757,6 +757,8 @@ regulator_enable_error: regulator_disable(par->vbat_reg); reset_oled_error: fb_deferred_io_cleanup(info); +fb_defio_error: + __free_pages(vmem, get_order(vmem_size)); fb_alloc_error: framebuffer_release(info); return ret; diff --git a/drivers/video/fbdev/tcx.c b/drivers/video/fbdev/tcx.c index f9a0085ad72b..ca9e84e8d860 100644 --- a/drivers/video/fbdev/tcx.c +++ b/drivers/video/fbdev/tcx.c @@ -428,7 +428,7 @@ static int tcx_probe(struct platform_device *op) j = i; break; } - par->mmap_map[i].poff = op->resource[j].start; + par->mmap_map[i].poff = op->resource[j].start - info->fix.smem_start; } info->fbops = &tcx_ops; diff --git a/drivers/video/fbdev/tridentfb.c b/drivers/video/fbdev/tridentfb.c index 516cf2a18757..17b7253b8fbe 100644 --- a/drivers/video/fbdev/tridentfb.c +++ b/drivers/video/fbdev/tridentfb.c @@ -1631,7 +1631,7 @@ static int trident_pci_probe(struct pci_dev *dev, } if (noaccel) { - printk(KERN_DEBUG "disabling acceleration\n"); + dev_dbg(&dev->dev, "disabling acceleration\n"); info->flags |= FBINFO_HWACCEL_DISABLED; info->pixmap.scan_align = 1; } @@ -1693,7 +1693,7 @@ static int trident_pci_probe(struct pci_dev *dev, info->var.activate |= FB_ACTIVATE_NOW; info->device = &dev->dev; if (register_framebuffer(info) < 0) { - printk(KERN_ERR "tridentfb: could not register framebuffer\n"); + dev_err(&dev->dev, "could not register framebuffer\n"); fb_dealloc_cmap(&info->cmap); err = -EINVAL; goto out_unmap2; diff --git a/drivers/video/fbdev/valkyriefb.c b/drivers/video/fbdev/valkyriefb.c index 91d070ef6989..6ff059ee1694 100644 --- a/drivers/video/fbdev/valkyriefb.c +++ b/drivers/video/fbdev/valkyriefb.c @@ -329,11 +329,13 @@ static int __init valkyriefb_init(void) if (of_address_to_resource(dp, 0, &r)) { printk(KERN_ERR "can't find address for valkyrie\n"); + of_node_put(dp); return 0; } frame_buffer_phys = r.start; cmap_regs_phys = r.start + 0x304000; + of_node_put(dp); } #endif /* ppc (!CONFIG_MAC) */ diff --git a/drivers/video/fbdev/vesafb.c b/drivers/video/fbdev/vesafb.c index a81df8865143..f135033c22fb 100644 --- a/drivers/video/fbdev/vesafb.c +++ b/drivers/video/fbdev/vesafb.c @@ -314,8 +314,8 @@ static int vesafb_probe(struct platform_device *dev) #endif if (!request_mem_region(vesafb_fix.smem_start, size_total, "vesafb")) { - printk(KERN_WARNING - "vesafb: cannot reserve video memory at 0x%lx\n", + dev_warn(&dev->dev, + "cannot reserve video memory at 0x%lx\n", vesafb_fix.smem_start); /* We cannot make this fatal. Sometimes this comes from magic spaces our resource handlers simply don't know about */ @@ -333,12 +333,12 @@ static int vesafb_probe(struct platform_device *dev) par->base = si->lfb_base; par->size = size_total; - printk(KERN_INFO "vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n", + dev_info(&dev->dev, "mode is %dx%dx%d, linelength=%d, pages=%d\n", vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, vesafb_fix.line_length, si->pages); if (si->vesapm_seg) { - printk(KERN_INFO "vesafb: protected mode interface info at %04x:%04x\n", + dev_info(&dev->dev, "protected mode interface info at %04x:%04x\n", si->vesapm_seg, si->vesapm_off); } @@ -352,9 +352,10 @@ static int vesafb_probe(struct platform_device *dev) pmi_base = (unsigned short *)phys_to_virt(pmi_phys); pmi_start = (void*)((char*)pmi_base + pmi_base[1]); pmi_pal = (void*)((char*)pmi_base + pmi_base[2]); - printk(KERN_INFO "vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal); + dev_info(&dev->dev, "pmi: set display start = %p, set palette = %p\n", + pmi_start, pmi_pal); if (pmi_base[3]) { - printk(KERN_INFO "vesafb: pmi: ports = "); + dev_info(&dev->dev, "pmi: ports = "); for (i = pmi_base[3]/2; pmi_base[i] != 0xffff; i++) printk("%x ", pmi_base[i]); printk("\n"); @@ -365,14 +366,14 @@ static int vesafb_probe(struct platform_device *dev) * Rules are: we have to set up a descriptor for the requested * memory area and pass it in the ES register to the BIOS function. */ - printk(KERN_INFO "vesafb: can't handle memory requests, pmi disabled\n"); + dev_info(&dev->dev, "can't handle memory requests, pmi disabled\n"); ypan = pmi_setpal = 0; } } } if (vesafb_defined.bits_per_pixel == 8 && !pmi_setpal && !vga_compat) { - printk(KERN_WARNING "vesafb: hardware palette is unchangeable,\n" + dev_warn(&dev->dev, "hardware palette is unchangeable,\n" " colors may be incorrect\n"); vesafb_fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; } @@ -380,10 +381,10 @@ static int vesafb_probe(struct platform_device *dev) vesafb_defined.xres_virtual = vesafb_defined.xres; vesafb_defined.yres_virtual = vesafb_fix.smem_len / vesafb_fix.line_length; if (ypan && vesafb_defined.yres_virtual > vesafb_defined.yres) { - printk(KERN_INFO "vesafb: scrolling: %s using protected mode interface, yres_virtual=%d\n", + dev_info(&dev->dev, "scrolling: %s using protected mode interface, yres_virtual=%d\n", (ypan > 1) ? "ywrap" : "ypan",vesafb_defined.yres_virtual); } else { - printk(KERN_INFO "vesafb: scrolling: redraw\n"); + dev_info(&dev->dev, "scrolling: redraw\n"); vesafb_defined.yres_virtual = vesafb_defined.yres; ypan = 0; } @@ -410,7 +411,7 @@ static int vesafb_probe(struct platform_device *dev) vesafb_defined.bits_per_pixel; } - printk(KERN_INFO "vesafb: %s: " + dev_info(&dev->dev, "%s: " "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", (vesafb_defined.bits_per_pixel > 8) ? "Truecolor" : (vga_compat || pmi_setpal) ? @@ -453,14 +454,14 @@ static int vesafb_probe(struct platform_device *dev) } if (!info->screen_base) { - printk(KERN_ERR - "vesafb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n", + dev_err(&dev->dev, + "abort, cannot ioremap video memory 0x%x @ 0x%lx\n", vesafb_fix.smem_len, vesafb_fix.smem_start); err = -EIO; goto err_release_region; } - printk(KERN_INFO "vesafb: framebuffer at 0x%lx, mapped to 0x%p, " + dev_info(&dev->dev, "framebuffer at 0x%lx, mapped to 0x%p, " "using %dk, total %dk\n", vesafb_fix.smem_start, info->screen_base, size_remap/1024, size_total/1024); diff --git a/drivers/video/fbdev/vga16fb.c b/drivers/video/fbdev/vga16fb.c index eedab14c7d51..6b81337a4909 100644 --- a/drivers/video/fbdev/vga16fb.c +++ b/drivers/video/fbdev/vga16fb.c @@ -1319,7 +1319,12 @@ static int vga16fb_probe(struct platform_device *dev) if (ret) return ret; - printk(KERN_DEBUG "vga16fb: initializing\n"); + dev_dbg(&dev->dev, "initializing\n"); + if (!request_mem_region(vga16fb_fix.smem_start, vga16fb_fix.smem_len, + "vga16b")) { + dev_err(&dev->dev, "cannot reserve video memory at 0x%lx\n", + vga16fb_fix.smem_start); + } info = framebuffer_alloc(sizeof(struct vga16fb_par), &dev->dev); if (!info) { @@ -1331,12 +1336,12 @@ static int vga16fb_probe(struct platform_device *dev) info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS_BASE, 0); if (!info->screen_base) { - printk(KERN_ERR "vga16fb: unable to map device\n"); + dev_err(&dev->dev, "unable to map device\n"); ret = -ENOMEM; goto err_ioremap; } - printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base); + dev_info(&dev->dev, "mapped to 0x%p\n", info->screen_base); par = info->par; par->isVGA = screen_info_video_type(si) == VIDEO_TYPE_VGAC; @@ -1364,13 +1369,13 @@ static int vga16fb_probe(struct platform_device *dev) i = (info->var.bits_per_pixel == 8) ? 256 : 16; ret = fb_alloc_cmap(&info->cmap, i, 0); if (ret) { - printk(KERN_ERR "vga16fb: unable to allocate colormap\n"); + dev_err(&dev->dev, "unable to allocate colormap\n"); ret = -ENOMEM; goto err_alloc_cmap; } if (vga16fb_check_var(&info->var, info)) { - printk(KERN_ERR "vga16fb: unable to validate variable\n"); + dev_err(&dev->dev, "unable to validate variable\n"); ret = -EINVAL; goto err_check_var; } @@ -1381,7 +1386,7 @@ static int vga16fb_probe(struct platform_device *dev) if (ret) goto err_check_var; if (register_framebuffer(info) < 0) { - printk(KERN_ERR "vga16fb: unable to register framebuffer\n"); + dev_err(&dev->dev, "unable to register framebuffer\n"); ret = -EINVAL; goto err_check_var; } @@ -1398,6 +1403,8 @@ static int vga16fb_probe(struct platform_device *dev) err_ioremap: framebuffer_release(info); err_fb_alloc: + release_mem_region(vga16fb_fix.smem_start, + vga16fb_fix.smem_len); return ret; } @@ -1407,6 +1414,8 @@ static void vga16fb_remove(struct platform_device *dev) if (info) unregister_framebuffer(info); + release_mem_region(vga16fb_fix.smem_start, + vga16fb_fix.smem_len); } static const struct platform_device_id vga16fb_driver_id_table[] = { |
