diff options
Diffstat (limited to 'drivers/gpu/drm/tiny/simpledrm.c')
-rw-r--r-- | drivers/gpu/drm/tiny/simpledrm.c | 140 |
1 files changed, 88 insertions, 52 deletions
diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index 162eb44dcba8..63881a3754f8 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -3,6 +3,7 @@ #include <linux/clk.h> #include <linux/of_clk.h> #include <linux/minmax.h> +#include <linux/of_address.h> #include <linux/platform_data/simplefb.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> @@ -184,6 +185,31 @@ simplefb_get_format_of(struct drm_device *dev, struct device_node *of_node) return simplefb_get_validated_format(dev, format); } +static struct resource * +simplefb_get_memory_of(struct drm_device *dev, struct device_node *of_node) +{ + struct device_node *np; + struct resource *res; + int err; + + np = of_parse_phandle(of_node, "memory-region", 0); + if (!np) + return NULL; + + res = devm_kzalloc(dev->dev, sizeof(*res), GFP_KERNEL); + if (!res) + return ERR_PTR(-ENOMEM); + + err = of_address_to_resource(np, 0, res); + if (err) + return ERR_PTR(err); + + if (of_get_property(of_node, "reg", NULL)) + drm_warn(dev, "preferring \"memory-region\" over \"reg\" property\n"); + + return res; +} + /* * Simple Framebuffer device */ @@ -208,7 +234,7 @@ struct simpledrm_device { unsigned int pitch; /* memory management */ - void __iomem *screen_base; + struct iosys_map screen_base; /* modesetting */ uint32_t formats[8]; @@ -446,25 +472,6 @@ static int simpledrm_device_init_regulators(struct simpledrm_device *sdev) * Modesetting */ -/* - * Support all formats of simplefb and maybe more; in order - * of preference. The display's update function will do any - * conversion necessary. - * - * TODO: Add blit helpers for remaining formats and uncomment - * constants. - */ -static const uint32_t simpledrm_primary_plane_formats[] = { - DRM_FORMAT_XRGB8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_RGB565, - //DRM_FORMAT_XRGB1555, - //DRM_FORMAT_ARGB1555, - DRM_FORMAT_RGB888, - DRM_FORMAT_XRGB2101010, - DRM_FORMAT_ARGB2101010, -}; - static const uint64_t simpledrm_primary_plane_format_modifiers[] = { DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID @@ -492,15 +499,15 @@ static void simpledrm_primary_plane_helper_atomic_update(struct drm_plane *plane drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); drm_atomic_for_each_plane_damage(&iter, &damage) { - struct iosys_map dst = IOSYS_MAP_INIT_VADDR(sdev->screen_base); struct drm_rect dst_clip = plane_state->dst; + struct iosys_map dst = sdev->screen_base; if (!drm_rect_intersect(&dst_clip, &damage)) continue; iosys_map_incr(&dst, drm_fb_clip_offset(sdev->pitch, sdev->format, &dst_clip)); - drm_fb_blit(&dst, &sdev->pitch, sdev->format->format, shadow_plane_state->data, fb, - &damage); + drm_fb_blit(&dst, &sdev->pitch, sdev->format->format, shadow_plane_state->data, + fb, &damage); } drm_dev_exit(idx); @@ -519,7 +526,7 @@ static void simpledrm_primary_plane_helper_atomic_disable(struct drm_plane *plan return; /* Clear screen to black if disabled */ - memset_io(sdev->screen_base, 0, sdev->pitch * sdev->mode.vdisplay); + iosys_map_memset(&sdev->screen_base, 0, 0, sdev->pitch * sdev->mode.vdisplay); drm_dev_exit(idx); } @@ -623,8 +630,7 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv, struct drm_device *dev; int width, height, stride; const struct drm_format_info *format; - struct resource *res, *mem; - void __iomem *screen_base; + struct resource *res, *mem = NULL; struct drm_plane *primary_plane; struct drm_crtc *crtc; struct drm_encoder *encoder; @@ -676,6 +682,9 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv, format = simplefb_get_format_of(dev, of_node); if (IS_ERR(format)) return ERR_CAST(format); + mem = simplefb_get_memory_of(dev, of_node); + if (IS_ERR(mem)) + return ERR_CAST(mem); } else { drm_err(dev, "no simplefb configuration found\n"); return ERR_PTR(-ENODEV); @@ -698,31 +707,55 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv, * Memory management */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return ERR_PTR(-EINVAL); + if (mem) { + void *screen_base; - ret = devm_aperture_acquire_from_firmware(dev, res->start, resource_size(res)); - if (ret) { - drm_err(dev, "could not acquire memory range %pr: error %d\n", res, ret); - return ERR_PTR(ret); - } + ret = devm_aperture_acquire_from_firmware(dev, mem->start, resource_size(mem)); + if (ret) { + drm_err(dev, "could not acquire memory range %pr: %d\n", mem, ret); + return ERR_PTR(ret); + } - mem = devm_request_mem_region(&pdev->dev, res->start, resource_size(res), drv->name); - if (!mem) { - /* - * We cannot make this fatal. Sometimes this comes from magic - * spaces our resource handlers simply don't know about. Use - * the I/O-memory resource as-is and try to map that instead. - */ - drm_warn(dev, "could not acquire memory region %pr\n", res); - mem = res; - } + drm_dbg(dev, "using system memory framebuffer at %pr\n", mem); - screen_base = devm_ioremap_wc(&pdev->dev, mem->start, resource_size(mem)); - if (!screen_base) - return ERR_PTR(-ENOMEM); - sdev->screen_base = screen_base; + screen_base = devm_memremap(dev->dev, mem->start, resource_size(mem), MEMREMAP_WC); + if (IS_ERR(screen_base)) + return screen_base; + + iosys_map_set_vaddr(&sdev->screen_base, screen_base); + } else { + void __iomem *screen_base; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return ERR_PTR(-EINVAL); + + ret = devm_aperture_acquire_from_firmware(dev, res->start, resource_size(res)); + if (ret) { + drm_err(dev, "could not acquire memory range %pr: %d\n", &res, ret); + return ERR_PTR(ret); + } + + drm_dbg(dev, "using I/O memory framebuffer at %pr\n", res); + + mem = devm_request_mem_region(&pdev->dev, res->start, resource_size(res), + drv->name); + if (!mem) { + /* + * We cannot make this fatal. Sometimes this comes from magic + * spaces our resource handlers simply don't know about. Use + * the I/O-memory resource as-is and try to map that instead. + */ + drm_warn(dev, "could not acquire memory region %pr\n", res); + mem = res; + } + + screen_base = devm_ioremap_wc(&pdev->dev, mem->start, resource_size(mem)); + if (!screen_base) + return ERR_PTR(-ENOMEM); + + iosys_map_set_vaddr_iomem(&sdev->screen_base, screen_base); + } /* * Modesetting @@ -739,14 +772,12 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv, dev->mode_config.max_width = max_width; dev->mode_config.min_height = height; dev->mode_config.max_height = max_height; - dev->mode_config.preferred_depth = format->cpp[0] * 8; + dev->mode_config.preferred_depth = format->depth; dev->mode_config.funcs = &simpledrm_mode_config_funcs; /* Primary plane */ nformats = drm_fb_build_fourcc_list(dev, &format->format, 1, - simpledrm_primary_plane_formats, - ARRAY_SIZE(simpledrm_primary_plane_formats), sdev->formats, ARRAY_SIZE(sdev->formats)); primary_plane = &sdev->primary_plane; @@ -823,6 +854,7 @@ static int simpledrm_probe(struct platform_device *pdev) { struct simpledrm_device *sdev; struct drm_device *dev; + unsigned int color_mode; int ret; sdev = simpledrm_device_create(&simpledrm_driver, pdev); @@ -834,7 +866,11 @@ static int simpledrm_probe(struct platform_device *pdev) if (ret) return ret; - drm_fbdev_generic_setup(dev, 0); + color_mode = drm_format_info_bpp(sdev->format, 0); + if (color_mode == 16) + color_mode = sdev->format->depth; // can be 15 or 16 + + drm_fbdev_generic_setup(dev, color_mode); return 0; } |