diff options
author | Bartlomiej Zolnierkiewicz | 2018-09-26 15:54:31 +0200 |
---|---|---|
committer | Bartlomiej Zolnierkiewicz | 2018-09-26 15:54:31 +0200 |
commit | aaccf3c97418f169afdbb5855e9cbcbda34e90fd (patch) | |
tree | 5d4207e67958bdbc23288cf30178692f5534e1a0 /drivers/video | |
parent | f39684524b391c5a7ed0ac44db4fec3357af1c5d (diff) | |
parent | 6bf4ca7fbc85d80446ac01c0d1d77db4d91a6d84 (diff) |
Merge tag 'v4.19-rc5' of https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux into fbdev-for-next
Sync with upstream (which now contains fbdev-v4.19 changes) to
prepare a base for fbdev-v4.20 changes.
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/backlight/adp8860_bl.c | 1 | ||||
-rw-r--r-- | drivers/video/backlight/pwm_bl.c | 232 | ||||
-rw-r--r-- | drivers/video/fbdev/efifb.c | 51 | ||||
-rw-r--r-- | drivers/video/fbdev/hyperv_fb.c | 6 | ||||
-rw-r--r-- | drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c | 1 |
5 files changed, 268 insertions, 23 deletions
diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 16119bde9750..f1dc41cf19e3 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -690,6 +690,7 @@ static int adp8860_probe(struct i2c_client *client, switch (ADP8860_MANID(reg_val)) { case ADP8863_MANUFID: data->gdwn_dis = !!pdata->gdwn_dis; + /* fall through */ case ADP8860_MANUFID: data->en_ambl_sens = !!pdata->en_ambl_sens; break; diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 44ac5bde4e9d..bdfcc0a71db1 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -143,11 +143,116 @@ static const struct backlight_ops pwm_backlight_ops = { }; #ifdef CONFIG_OF +#define PWM_LUMINANCE_SCALE 10000 /* luminance scale */ + +/* An integer based power function */ +static u64 int_pow(u64 base, int exp) +{ + u64 result = 1; + + while (exp) { + if (exp & 1) + result *= base; + exp >>= 1; + base *= base; + } + + return result; +} + +/* + * CIE lightness to PWM conversion. + * + * The CIE 1931 lightness formula is what actually describes how we perceive + * light: + * Y = (L* / 902.3) if L* ≤ 0.08856 + * Y = ((L* + 16) / 116)^3 if L* > 0.08856 + * + * Where Y is the luminance, the amount of light coming out of the screen, and + * is a number between 0.0 and 1.0; and L* is the lightness, how bright a human + * perceives the screen to be, and is a number between 0 and 100. + * + * The following function does the fixed point maths needed to implement the + * above formula. + */ +static u64 cie1931(unsigned int lightness, unsigned int scale) +{ + u64 retval; + + lightness *= 100; + if (lightness <= (8 * scale)) { + retval = DIV_ROUND_CLOSEST_ULL(lightness * 10, 9023); + } else { + retval = int_pow((lightness + (16 * scale)) / 116, 3); + retval = DIV_ROUND_CLOSEST_ULL(retval, (scale * scale)); + } + + return retval; +} + +/* + * Create a default correction table for PWM values to create linear brightness + * for LED based backlights using the CIE1931 algorithm. + */ +static +int pwm_backlight_brightness_default(struct device *dev, + struct platform_pwm_backlight_data *data, + unsigned int period) +{ + unsigned int counter = 0; + unsigned int i, n; + u64 retval; + + /* + * Count the number of bits needed to represent the period number. The + * number of bits is used to calculate the number of levels used for the + * brightness-levels table, the purpose of this calculation is have a + * pre-computed table with enough levels to get linear brightness + * perception. The period is divided by the number of bits so for a + * 8-bit PWM we have 255 / 8 = 32 brightness levels or for a 16-bit PWM + * we have 65535 / 16 = 4096 brightness levels. + * + * Note that this method is based on empirical testing on different + * devices with PWM of 8 and 16 bits of resolution. + */ + n = period; + while (n) { + counter += n % 2; + n >>= 1; + } + + data->max_brightness = DIV_ROUND_UP(period, counter); + data->levels = devm_kcalloc(dev, data->max_brightness, + sizeof(*data->levels), GFP_KERNEL); + if (!data->levels) + return -ENOMEM; + + /* Fill the table using the cie1931 algorithm */ + for (i = 0; i < data->max_brightness; i++) { + retval = cie1931((i * PWM_LUMINANCE_SCALE) / + data->max_brightness, PWM_LUMINANCE_SCALE) * + period; + retval = DIV_ROUND_CLOSEST_ULL(retval, PWM_LUMINANCE_SCALE); + if (retval > UINT_MAX) + return -EINVAL; + data->levels[i] = (unsigned int)retval; + } + + data->dft_brightness = data->max_brightness / 2; + data->max_brightness--; + + return 0; +} + static int pwm_backlight_parse_dt(struct device *dev, struct platform_pwm_backlight_data *data) { struct device_node *node = dev->of_node; + unsigned int num_levels = 0; + unsigned int levels_count; + unsigned int num_steps = 0; struct property *prop; + unsigned int *table; int length; u32 value; int ret; @@ -157,16 +262,20 @@ static int pwm_backlight_parse_dt(struct device *dev, memset(data, 0, sizeof(*data)); - /* determine the number of brightness levels */ + /* + * Determine the number of brightness levels, if this property is not + * set a default table of brightness levels will be used. + */ prop = of_find_property(node, "brightness-levels", &length); if (!prop) - return -EINVAL; + return 0; data->max_brightness = length / sizeof(u32); /* read brightness levels from DT property */ if (data->max_brightness > 0) { size_t size = sizeof(*data->levels) * data->max_brightness; + unsigned int i, j, n = 0; data->levels = devm_kzalloc(dev, size, GFP_KERNEL); if (!data->levels) @@ -184,6 +293,84 @@ static int pwm_backlight_parse_dt(struct device *dev, return ret; data->dft_brightness = value; + + /* + * This property is optional, if is set enables linear + * interpolation between each of the values of brightness levels + * and creates a new pre-computed table. + */ + of_property_read_u32(node, "num-interpolated-steps", + &num_steps); + + /* + * Make sure that there is at least two entries in the + * brightness-levels table, otherwise we can't interpolate + * between two points. + */ + if (num_steps) { + if (data->max_brightness < 2) { + dev_err(dev, "can't interpolate\n"); + return -EINVAL; + } + + /* + * Recalculate the number of brightness levels, now + * taking in consideration the number of interpolated + * steps between two levels. + */ + for (i = 0; i < data->max_brightness - 1; i++) { + if ((data->levels[i + 1] - data->levels[i]) / + num_steps) + num_levels += num_steps; + else + num_levels++; + } + num_levels++; + dev_dbg(dev, "new number of brightness levels: %d\n", + num_levels); + + /* + * Create a new table of brightness levels with all the + * interpolated steps. + */ + size = sizeof(*table) * num_levels; + table = devm_kzalloc(dev, size, GFP_KERNEL); + if (!table) + return -ENOMEM; + + /* Fill the interpolated table. */ + levels_count = 0; + for (i = 0; i < data->max_brightness - 1; i++) { + value = data->levels[i]; + n = (data->levels[i + 1] - value) / num_steps; + if (n > 0) { + for (j = 0; j < num_steps; j++) { + table[levels_count] = value; + value += n; + levels_count++; + } + } else { + table[levels_count] = data->levels[i]; + levels_count++; + } + } + table[levels_count] = data->levels[i]; + + /* + * As we use interpolation lets remove current + * brightness levels table and replace for the + * new interpolated table. + */ + devm_kfree(dev, data->levels); + data->levels = table; + + /* + * Reassign max_brightness value to the new total number + * of brightness levels. + */ + data->max_brightness = num_levels; + } + data->max_brightness--; } @@ -211,6 +398,14 @@ static int pwm_backlight_parse_dt(struct device *dev, { return -ENODEV; } + +static +int pwm_backlight_brightness_default(struct device *dev, + struct platform_pwm_backlight_data *data, + unsigned int period) +{ + return -ENODEV; +} #endif static int pwm_backlight_initial_power_state(const struct pwm_bl_data *pb) @@ -251,7 +446,9 @@ static int pwm_backlight_probe(struct platform_device *pdev) struct backlight_device *bl; struct device_node *node = pdev->dev.of_node; struct pwm_bl_data *pb; + struct pwm_state state; struct pwm_args pargs; + unsigned int i; int ret; if (!data) { @@ -276,17 +473,6 @@ static int pwm_backlight_probe(struct platform_device *pdev) goto err_alloc; } - if (data->levels) { - unsigned int i; - - for (i = 0; i <= data->max_brightness; i++) - if (data->levels[i] > pb->scale) - pb->scale = data->levels[i]; - - pb->levels = data->levels; - } else - pb->scale = data->max_brightness; - pb->notify = data->notify; pb->notify_after = data->notify_after; pb->check_fb = data->check_fb; @@ -353,6 +539,26 @@ static int pwm_backlight_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "got pwm for backlight\n"); + if (!data->levels) { + /* Get the PWM period (in nanoseconds) */ + pwm_get_state(pb->pwm, &state); + + ret = pwm_backlight_brightness_default(&pdev->dev, data, + state.period); + if (ret < 0) { + dev_err(&pdev->dev, + "failed to setup default brightness table\n"); + goto err_alloc; + } + } + + for (i = 0; i <= data->max_brightness; i++) { + if (data->levels[i] > pb->scale) + pb->scale = data->levels[i]; + + pb->levels = data->levels; + } + /* * FIXME: pwm_apply_args() should be removed when switching to * the atomic PWM API. diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index 52bf39f93888..3946649b85c8 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c @@ -43,7 +43,7 @@ struct bmp_dib_header { } __packed; static bool request_mem_succeeded = false; -static bool nowc = false; +static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC; static struct fb_var_screeninfo efifb_defined = { .activate = FB_ACTIVATE_NOW, @@ -249,8 +249,12 @@ static inline void efifb_show_boot_graphics(struct fb_info *info) {} static void efifb_destroy(struct fb_info *info) { - if (info->screen_base) - iounmap(info->screen_base); + if (info->screen_base) { + if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC)) + iounmap(info->screen_base); + else + memunmap(info->screen_base); + } if (request_mem_succeeded) release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size); @@ -285,7 +289,7 @@ static int efifb_setup(char *options) else if (!strncmp(this_opt, "width:", 6)) screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0); else if (!strcmp(this_opt, "nowc")) - nowc = true; + mem_flags &= ~EFI_MEMORY_WC; } } @@ -345,6 +349,7 @@ static int efifb_probe(struct platform_device *dev) unsigned int size_remap; unsigned int size_total; char *option = NULL; + efi_memory_desc_t md; if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled) return -ENODEV; @@ -453,12 +458,35 @@ static int efifb_probe(struct platform_device *dev) info->apertures->ranges[0].base = efifb_fix.smem_start; info->apertures->ranges[0].size = size_remap; - if (nowc) - info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len); - else - info->screen_base = ioremap_wc(efifb_fix.smem_start, efifb_fix.smem_len); + if (!efi_mem_desc_lookup(efifb_fix.smem_start, &md)) { + if ((efifb_fix.smem_start + efifb_fix.smem_len) > + (md.phys_addr + (md.num_pages << EFI_PAGE_SHIFT))) { + pr_err("efifb: video memory @ 0x%lx spans multiple EFI memory regions\n", + efifb_fix.smem_start); + err = -EIO; + goto err_release_fb; + } + /* + * If the UEFI memory map covers the efifb region, we may only + * remap it using the attributes the memory map prescribes. + */ + mem_flags |= EFI_MEMORY_WT | EFI_MEMORY_WB; + mem_flags &= md.attribute; + } + if (mem_flags & EFI_MEMORY_WC) + info->screen_base = ioremap_wc(efifb_fix.smem_start, + efifb_fix.smem_len); + else if (mem_flags & EFI_MEMORY_UC) + info->screen_base = ioremap(efifb_fix.smem_start, + efifb_fix.smem_len); + else if (mem_flags & EFI_MEMORY_WT) + info->screen_base = memremap(efifb_fix.smem_start, + efifb_fix.smem_len, MEMREMAP_WT); + else if (mem_flags & EFI_MEMORY_WB) + info->screen_base = memremap(efifb_fix.smem_start, + efifb_fix.smem_len, MEMREMAP_WB); if (!info->screen_base) { - pr_err("efifb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n", + pr_err("efifb: abort, cannot remap video memory 0x%x @ 0x%lx\n", efifb_fix.smem_len, efifb_fix.smem_start); err = -EIO; goto err_release_fb; @@ -554,7 +582,10 @@ err_fb_dealoc: err_groups: sysfs_remove_groups(&dev->dev.kobj, efifb_groups); err_unmap: - iounmap(info->screen_base); + if (mem_flags & (EFI_MEMORY_UC | EFI_MEMORY_WC)) + iounmap(info->screen_base); + else + memunmap(info->screen_base); err_release_fb: framebuffer_release(info); err_release_mem: diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index 2fd49b2358f8..403d8cd3e582 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -912,6 +912,9 @@ static struct hv_driver hvfb_drv = { .id_table = id_table, .probe = hvfb_probe, .remove = hvfb_remove, + .driver = { + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, }; static int hvfb_pci_stub_probe(struct pci_dev *pdev, @@ -929,6 +932,9 @@ static struct pci_driver hvfb_pci_stub_driver = { .id_table = pci_stub_id_table, .probe = hvfb_pci_stub_probe, .remove = hvfb_pci_stub_remove, + .driver = { + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + } }; static int __init hvfb_drv_init(void) diff --git a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c index 81aadb3e0913..47f0459e3551 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c @@ -12,6 +12,7 @@ #include <linux/completion.h> #include <linux/delay.h> #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/gpio/consumer.h> |