diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-02 07:59:23 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-02 07:59:23 -0700 |
commit | 320b164abb32db876866a4ff8c2cb710524ac6ea (patch) | |
tree | 1f79119cde6e24c9f1d01fb1e51252bca7c4cdd5 /drivers/gpu/drm/panel/panel-arm-versatile.c | |
parent | 0adb32858b0bddf4ada5f364a84ed60b196dbcda (diff) | |
parent | 694f54f680f7fd8e9561928fbfc537d9afbc3d79 (diff) | |
download | linux-320b164abb32db876866a4ff8c2cb710524ac6ea.tar.gz linux-320b164abb32db876866a4ff8c2cb710524ac6ea.tar.bz2 linux-320b164abb32db876866a4ff8c2cb710524ac6ea.zip |
Merge tag 'drm-for-v4.17' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie:
"Cannonlake and Vega12 support are probably the two major things. This
pull lacks nouveau, Ben had some unforseen leave and a few other
blockers so we'll see how things look or maybe leave it for this merge
window.
core:
- Device links to handle sound/gpu pm dependency
- Color encoding/range properties
- Plane clipping into plane check helper
- Backlight helpers
- DP TP4 + HBR3 helper support
amdgpu:
- Vega12 support
- Enable DC by default on all supported GPUs
- Powerplay restructuring and cleanup
- DC bandwidth calc updates
- DC backlight on pre-DCE11
- TTM backing store dropping support
- SR-IOV fixes
- Adding "wattman" like functionality
- DC crc support
- Improved DC dual-link handling
amdkfd:
- GPUVM support for dGPU
- KFD events for dGPU
- Enable PCIe atomics for dGPUs
- HSA process eviction support
- Live-lock fixes for process eviction
- VM page table allocation fix for large-bar systems
panel:
- Raydium RM68200
- AUO G104SN02 V2
- KEO TX31D200VM0BAA
- ARM Versatile panels
i915:
- Cannonlake support enabled
- AUX-F port support added
- Icelake base enabling until internal milestone of forcewake support
- Query uAPI interface (used for GPU topology information currently)
- Compressed framebuffer support for sprites
- kmem cache shrinking when GPU is idle
- Avoid boosting GPU when waited item is being processed already
- Avoid retraining LSPCON link unnecessarily
- Decrease request signaling latency
- Deprecation of I915_SET_COLORKEY_NONE
- Kerneldoc and compiler warning cleanup for upcoming CI enforcements
- Full range ycbcr toggling
- HDCP support
i915/gvt:
- Big refactor for shadow ppgtt
- KBL context save/restore via LRI cmd (Weinan)
- Properly unmap dma for guest page (Changbin)
vmwgfx:
- Lots of various improvements
etnaviv:
- Use the drm gpu scheduler
- prep work for GC7000L support
vc4:
- fix alpha blending
- Expose perf counters to userspace
pl111:
- Bandwidth checking/limiting
- Versatile panel support
sun4i:
- A83T HDMI support
- A80 support
- YUV plane support
- H3/H5 HDMI support
omapdrm:
- HPD support for DVI connector
- remove lots of static variables
msm:
- DSI updates from 10nm / SDM845
- fix for race condition with a3xx/a4xx fence completion irq
- some refactoring/prep work for eventual a6xx support (ie. when we
have a userspace)
- a5xx debugfs enhancements
- some mdp5 fixes/cleanups to prepare for eventually merging
writeback
- support (ie. when we have a userspace)
tegra:
- mmap() fixes for fbdev devices
- Overlay plane for hw cursor fix
- dma-buf cache maintenance support
mali-dp:
- YUV->RGB conversion support
rockchip:
- rk3399/chromebook fixes and improvements
rcar-du:
- LVDS support move to drm bridge
- DT bindings for R8A77995
- Driver/DT support for R8A77970
tilcdc:
- DRM panel support"
* tag 'drm-for-v4.17' of git://people.freedesktop.org/~airlied/linux: (1646 commits)
drm/i915: Fix hibernation with ACPI S0 target state
drm/i915/execlists: Use a locked clear_bit() for synchronisation with interrupt
drm/i915: Specify which engines to reset following semaphore/event lockups
drm/i915/dp: Write to SET_POWER dpcd to enable MST hub.
drm/amdkfd: Use ordered workqueue to restore processes
drm/amdgpu: Fix acquiring VM on large-BAR systems
drm/amd/pp: clean header file hwmgr.h
drm/amd/pp: use mlck_table.count for array loop index limit
drm: Fix uabi regression by allowing garbage mode->type from userspace
drm/amdgpu: Add an ATPX quirk for hybrid laptop
drm/amdgpu: fix spelling mistake: "asssert" -> "assert"
drm/amd/pp: Add new asic support in pp_psm.c
drm/amd/pp: Clean up powerplay code on Vega12
drm/amd/pp: Add smu irq handlers for legacy asics
drm/amd/pp: Fix set wrong temperature range on smu7
drm/amdgpu: Don't change preferred domian when fallback GTT v5
drm/vmwgfx: Bump version patchlevel and date
drm/vmwgfx: use monotonic event timestamps
drm/vmwgfx: Unpin the screen object backup buffer when not used
drm/vmwgfx: Stricter count of legacy surface device resources
...
Diffstat (limited to 'drivers/gpu/drm/panel/panel-arm-versatile.c')
-rw-r--r-- | drivers/gpu/drm/panel/panel-arm-versatile.c | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/drivers/gpu/drm/panel/panel-arm-versatile.c b/drivers/gpu/drm/panel/panel-arm-versatile.c new file mode 100644 index 000000000000..b428c4678106 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-arm-versatile.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Panel driver for the ARM Versatile family reference designs from + * ARM Limited. + * + * Author: + * Linus Walleij <linus.wallei@linaro.org> + * + * On the Versatile AB, these panels come mounted on daughterboards + * named "IB1" or "IB2" (Interface Board 1 & 2 respectively.) They + * are documented in ARM DUI 0225D Appendix C and D. These daughter + * boards support TFT display panels. + * + * - The IB1 is a passive board where the display connector defines a + * few wires for encoding the display type for autodetection, + * suitable display settings can then be looked up from this setting. + * The magic bits can be read out from the system controller. + * + * - The IB2 is a more complex board intended for GSM phone development + * with some logic and a control register, which needs to be accessed + * and the board display needs to be turned on explicitly. + * + * On the Versatile PB, a special CLCD adaptor board is available + * supporting the same displays as the Versatile AB, plus one more + * Epson QCIF display. + * + */ +#include <drm/drmP.h> +#include <drm/drm_panel.h> + +#include <linux/bitops.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#include <video/of_videomode.h> +#include <video/videomode.h> + +/* + * This configuration register in the Versatile and RealView + * family is uniformly present but appears more and more + * unutilized starting with the RealView series. + */ +#define SYS_CLCD 0x50 + +/* The Versatile can detect the connected panel type */ +#define SYS_CLCD_CLCDID_MASK (BIT(8)|BIT(9)|BIT(10)|BIT(11)|BIT(12)) +#define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8) +#define SYS_CLCD_ID_SHARP_8_4 (0x01 << 8) +#define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8) +#define SYS_CLCD_ID_SANYO_2_5 (0x07 << 8) +#define SYS_CLCD_ID_VGA (0x1f << 8) + +/* IB2 control register for the Versatile daughterboard */ +#define IB2_CTRL 0x00 +#define IB2_CTRL_LCD_SD BIT(1) /* 1 = shut down LCD */ +#define IB2_CTRL_LCD_BL_ON BIT(0) +#define IB2_CTRL_LCD_MASK (BIT(0)|BIT(1)) + +/** + * struct versatile_panel_type - lookup struct for the supported panels + */ +struct versatile_panel_type { + /** + * @name: the name of this panel + */ + const char *name; + /** + * @magic: the magic value from the detection register + */ + u32 magic; + /** + * @mode: the DRM display mode for this panel + */ + struct drm_display_mode mode; + /** + * @bus_flags: the DRM bus flags for this panel e.g. inverted clock + */ + u32 bus_flags; + /** + * @width_mm: the panel width in mm + */ + u32 width_mm; + /** + * @height_mm: the panel height in mm + */ + u32 height_mm; + /** + * @ib2: the panel may be connected on an IB2 daughterboard + */ + bool ib2; +}; + +/** + * struct versatile_panel - state container for the Versatile panels + */ +struct versatile_panel { + /** + * @dev: the container device + */ + struct device *dev; + /** + * @panel: the DRM panel instance for this device + */ + struct drm_panel panel; + /** + * @panel_type: the Versatile panel type as detected + */ + const struct versatile_panel_type *panel_type; + /** + * @map: map to the parent syscon where the main register reside + */ + struct regmap *map; + /** + * @ib2_map: map to the IB2 syscon, if applicable + */ + struct regmap *ib2_map; +}; + +static const struct versatile_panel_type versatile_panels[] = { + /* + * Sanyo TM38QV67A02A - 3.8 inch QVGA (320x240) Color TFT + * found on the Versatile AB IB1 connector or the Versatile + * PB adaptor board connector. + */ + { + .name = "Sanyo TM38QV67A02A", + .magic = SYS_CLCD_ID_SANYO_3_8, + .width_mm = 79, + .height_mm = 54, + .mode = { + .clock = 10000, + .hdisplay = 320, + .hsync_start = 320 + 6, + .hsync_end = 320 + 6 + 6, + .htotal = 320 + 6 + 6 + 6, + .vdisplay = 240, + .vsync_start = 240 + 5, + .vsync_end = 240 + 5 + 6, + .vtotal = 240 + 5 + 6 + 5, + .vrefresh = 116, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, + }, + }, + /* + * Sharp LQ084V1DG21 640x480 VGA Color TFT module + * found on the Versatile AB IB1 connector or the Versatile + * PB adaptor board connector. + */ + { + .name = "Sharp LQ084V1DG21", + .magic = SYS_CLCD_ID_SHARP_8_4, + .width_mm = 171, + .height_mm = 130, + .mode = { + .clock = 25000, + .hdisplay = 640, + .hsync_start = 640 + 24, + .hsync_end = 640 + 24 + 96, + .htotal = 640 + 24 + 96 + 24, + .vdisplay = 480, + .vsync_start = 480 + 11, + .vsync_end = 480 + 11 + 2, + .vtotal = 480 + 11 + 2 + 32, + .vrefresh = 60, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, + }, + }, + /* + * Epson L2F50113T00 - 2.2 inch QCIF 176x220 Color TFT + * found on the Versatile PB adaptor board connector. + */ + { + .name = "Epson L2F50113T00", + .magic = SYS_CLCD_ID_EPSON_2_2, + .width_mm = 34, + .height_mm = 45, + .mode = { + .clock = 62500, + .hdisplay = 176, + .hsync_start = 176 + 2, + .hsync_end = 176 + 2 + 3, + .htotal = 176 + 2 + 3 + 3, + .vdisplay = 220, + .vsync_start = 220 + 0, + .vsync_end = 220 + 0 + 2, + .vtotal = 220 + 0 + 2 + 1, + .vrefresh = 390, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, + }, + .bus_flags = DRM_BUS_FLAG_PIXDATA_NEGEDGE, + }, + /* + * Sanyo ALR252RGT 240x320 portrait display found on the + * Versatile AB IB2 daughterboard for GSM prototyping. + */ + { + .name = "Sanyo ALR252RGT", + .magic = SYS_CLCD_ID_SANYO_2_5, + .width_mm = 37, + .height_mm = 50, + .mode = { + .clock = 5400, + .hdisplay = 240, + .hsync_start = 240 + 10, + .hsync_end = 240 + 10 + 10, + .htotal = 240 + 10 + 10 + 20, + .vdisplay = 320, + .vsync_start = 320 + 2, + .vsync_end = 320 + 2 + 2, + .vtotal = 320 + 2 + 2 + 2, + .vrefresh = 116, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + }, + .bus_flags = DRM_BUS_FLAG_PIXDATA_NEGEDGE, + .ib2 = true, + }, +}; + +static inline struct versatile_panel * +to_versatile_panel(struct drm_panel *panel) +{ + return container_of(panel, struct versatile_panel, panel); +} + +static int versatile_panel_disable(struct drm_panel *panel) +{ + struct versatile_panel *vpanel = to_versatile_panel(panel); + + /* If we're on an IB2 daughterboard, turn off display */ + if (vpanel->ib2_map) { + dev_dbg(vpanel->dev, "disable IB2 display\n"); + regmap_update_bits(vpanel->ib2_map, + IB2_CTRL, + IB2_CTRL_LCD_MASK, + IB2_CTRL_LCD_SD); + } + + return 0; +} + +static int versatile_panel_enable(struct drm_panel *panel) +{ + struct versatile_panel *vpanel = to_versatile_panel(panel); + + /* If we're on an IB2 daughterboard, turn on display */ + if (vpanel->ib2_map) { + dev_dbg(vpanel->dev, "enable IB2 display\n"); + regmap_update_bits(vpanel->ib2_map, + IB2_CTRL, + IB2_CTRL_LCD_MASK, + IB2_CTRL_LCD_BL_ON); + } + + return 0; +} + +static int versatile_panel_get_modes(struct drm_panel *panel) +{ + struct drm_connector *connector = panel->connector; + struct versatile_panel *vpanel = to_versatile_panel(panel); + struct drm_display_mode *mode; + + strncpy(connector->display_info.name, vpanel->panel_type->name, + DRM_DISPLAY_INFO_LEN); + connector->display_info.width_mm = vpanel->panel_type->width_mm; + connector->display_info.height_mm = vpanel->panel_type->height_mm; + connector->display_info.bus_flags = vpanel->panel_type->bus_flags; + + mode = drm_mode_duplicate(panel->drm, &vpanel->panel_type->mode); + drm_mode_set_name(mode); + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + + mode->width_mm = vpanel->panel_type->width_mm; + mode->height_mm = vpanel->panel_type->height_mm; + drm_mode_probed_add(connector, mode); + + return 1; +} + +static const struct drm_panel_funcs versatile_panel_drm_funcs = { + .disable = versatile_panel_disable, + .enable = versatile_panel_enable, + .get_modes = versatile_panel_get_modes, +}; + +static int versatile_panel_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct versatile_panel *vpanel; + struct device *parent; + struct regmap *map; + int ret; + u32 val; + int i; + + parent = dev->parent; + if (!parent) { + dev_err(dev, "no parent for versatile panel\n"); + return -ENODEV; + } + map = syscon_node_to_regmap(parent->of_node); + if (IS_ERR(map)) { + dev_err(dev, "no regmap for versatile panel parent\n"); + return PTR_ERR(map); + } + + vpanel = devm_kzalloc(dev, sizeof(*vpanel), GFP_KERNEL); + if (!vpanel) + return -ENOMEM; + + ret = regmap_read(map, SYS_CLCD, &val); + if (ret) { + dev_err(dev, "cannot access syscon regs\n"); + return ret; + } + + val &= SYS_CLCD_CLCDID_MASK; + + for (i = 0; i < ARRAY_SIZE(versatile_panels); i++) { + const struct versatile_panel_type *pt; + + pt = &versatile_panels[i]; + if (pt->magic == val) { + vpanel->panel_type = pt; + break; + } + } + + /* No panel detected or VGA, let's leave this show */ + if (i == ARRAY_SIZE(versatile_panels)) { + dev_info(dev, "no panel detected\n"); + return -ENODEV; + } + + dev_info(dev, "detected: %s\n", vpanel->panel_type->name); + vpanel->dev = dev; + vpanel->map = map; + + /* Check if the panel is mounted on an IB2 daughterboard */ + if (vpanel->panel_type->ib2) { + vpanel->ib2_map = syscon_regmap_lookup_by_compatible( + "arm,versatile-ib2-syscon"); + if (IS_ERR(vpanel->ib2_map)) + vpanel->ib2_map = NULL; + else + dev_info(dev, "panel mounted on IB2 daughterboard\n"); + } + + drm_panel_init(&vpanel->panel); + vpanel->panel.dev = dev; + vpanel->panel.funcs = &versatile_panel_drm_funcs; + + return drm_panel_add(&vpanel->panel); +} + +static const struct of_device_id versatile_panel_match[] = { + { .compatible = "arm,versatile-tft-panel", }, + {}, +}; +MODULE_DEVICE_TABLE(of, versatile_panel_match); + +static struct platform_driver versatile_panel_driver = { + .probe = versatile_panel_probe, + .driver = { + .name = "versatile-tft-panel", + .of_match_table = versatile_panel_match, + }, +}; +module_platform_driver(versatile_panel_driver); + +MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); +MODULE_DESCRIPTION("ARM Versatile panel driver"); +MODULE_LICENSE("GPL v2"); |