14f2a8f58SJoel Stanley // SPDX-License-Identifier: GPL-2.0+ 24f2a8f58SJoel Stanley // Copyright 2018 IBM Corporation 34f2a8f58SJoel Stanley 44f2a8f58SJoel Stanley #include <linux/clk.h> 54f2a8f58SJoel Stanley #include <linux/reset.h> 64f2a8f58SJoel Stanley #include <linux/regmap.h> 74f2a8f58SJoel Stanley 84f2a8f58SJoel Stanley #include <drm/drm_crtc_helper.h> 94f2a8f58SJoel Stanley #include <drm/drm_device.h> 106bcfe8eaSDanilo Krummrich #include <drm/drm_fb_dma_helper.h> 114f2a8f58SJoel Stanley #include <drm/drm_fourcc.h> 12720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h> 13820c1707SThomas Zimmermann #include <drm/drm_gem_atomic_helper.h> 144a83c26aSDanilo Krummrich #include <drm/drm_gem_dma_helper.h> 154f2a8f58SJoel Stanley #include <drm/drm_panel.h> 164f2a8f58SJoel Stanley #include <drm/drm_simple_kms_helper.h> 174f2a8f58SJoel Stanley #include <drm/drm_vblank.h> 184f2a8f58SJoel Stanley 194f2a8f58SJoel Stanley #include "aspeed_gfx.h" 204f2a8f58SJoel Stanley 214f2a8f58SJoel Stanley static struct aspeed_gfx * 224f2a8f58SJoel Stanley drm_pipe_to_aspeed_gfx(struct drm_simple_display_pipe *pipe) 234f2a8f58SJoel Stanley { 244f2a8f58SJoel Stanley return container_of(pipe, struct aspeed_gfx, pipe); 254f2a8f58SJoel Stanley } 264f2a8f58SJoel Stanley 274f2a8f58SJoel Stanley static int aspeed_gfx_set_pixel_fmt(struct aspeed_gfx *priv, u32 *bpp) 284f2a8f58SJoel Stanley { 294f2a8f58SJoel Stanley struct drm_crtc *crtc = &priv->pipe.crtc; 304f2a8f58SJoel Stanley struct drm_device *drm = crtc->dev; 314f2a8f58SJoel Stanley const u32 format = crtc->primary->state->fb->format->format; 324f2a8f58SJoel Stanley u32 ctrl1; 334f2a8f58SJoel Stanley 344f2a8f58SJoel Stanley ctrl1 = readl(priv->base + CRT_CTRL1); 354f2a8f58SJoel Stanley ctrl1 &= ~CRT_CTRL_COLOR_MASK; 364f2a8f58SJoel Stanley 374f2a8f58SJoel Stanley switch (format) { 384f2a8f58SJoel Stanley case DRM_FORMAT_RGB565: 394f2a8f58SJoel Stanley dev_dbg(drm->dev, "Setting up RGB565 mode\n"); 404f2a8f58SJoel Stanley ctrl1 |= CRT_CTRL_COLOR_RGB565; 414f2a8f58SJoel Stanley *bpp = 16; 424f2a8f58SJoel Stanley break; 434f2a8f58SJoel Stanley case DRM_FORMAT_XRGB8888: 444f2a8f58SJoel Stanley dev_dbg(drm->dev, "Setting up XRGB8888 mode\n"); 454f2a8f58SJoel Stanley ctrl1 |= CRT_CTRL_COLOR_XRGB8888; 464f2a8f58SJoel Stanley *bpp = 32; 474f2a8f58SJoel Stanley break; 484f2a8f58SJoel Stanley default: 494f2a8f58SJoel Stanley dev_err(drm->dev, "Unhandled pixel format %08x\n", format); 504f2a8f58SJoel Stanley return -EINVAL; 514f2a8f58SJoel Stanley } 524f2a8f58SJoel Stanley 534f2a8f58SJoel Stanley writel(ctrl1, priv->base + CRT_CTRL1); 544f2a8f58SJoel Stanley 554f2a8f58SJoel Stanley return 0; 564f2a8f58SJoel Stanley } 574f2a8f58SJoel Stanley 584f2a8f58SJoel Stanley static void aspeed_gfx_enable_controller(struct aspeed_gfx *priv) 594f2a8f58SJoel Stanley { 604f2a8f58SJoel Stanley u32 ctrl1 = readl(priv->base + CRT_CTRL1); 614f2a8f58SJoel Stanley u32 ctrl2 = readl(priv->base + CRT_CTRL2); 624f2a8f58SJoel Stanley 63bce724faSJoel Stanley /* Set DAC source for display output to Graphics CRT (GFX) */ 64bce724faSJoel Stanley regmap_update_bits(priv->scu, priv->dac_reg, BIT(16), BIT(16)); 654f2a8f58SJoel Stanley 664f2a8f58SJoel Stanley writel(ctrl1 | CRT_CTRL_EN, priv->base + CRT_CTRL1); 674f2a8f58SJoel Stanley writel(ctrl2 | CRT_CTRL_DAC_EN, priv->base + CRT_CTRL2); 684f2a8f58SJoel Stanley } 694f2a8f58SJoel Stanley 704f2a8f58SJoel Stanley static void aspeed_gfx_disable_controller(struct aspeed_gfx *priv) 714f2a8f58SJoel Stanley { 724f2a8f58SJoel Stanley u32 ctrl1 = readl(priv->base + CRT_CTRL1); 734f2a8f58SJoel Stanley u32 ctrl2 = readl(priv->base + CRT_CTRL2); 744f2a8f58SJoel Stanley 754f2a8f58SJoel Stanley writel(ctrl1 & ~CRT_CTRL_EN, priv->base + CRT_CTRL1); 764f2a8f58SJoel Stanley writel(ctrl2 & ~CRT_CTRL_DAC_EN, priv->base + CRT_CTRL2); 774f2a8f58SJoel Stanley 78bce724faSJoel Stanley regmap_update_bits(priv->scu, priv->dac_reg, BIT(16), 0); 794f2a8f58SJoel Stanley } 804f2a8f58SJoel Stanley 814f2a8f58SJoel Stanley static void aspeed_gfx_crtc_mode_set_nofb(struct aspeed_gfx *priv) 824f2a8f58SJoel Stanley { 834f2a8f58SJoel Stanley struct drm_display_mode *m = &priv->pipe.crtc.state->adjusted_mode; 844f2a8f58SJoel Stanley u32 ctrl1, d_offset, t_count, bpp; 854f2a8f58SJoel Stanley int err; 864f2a8f58SJoel Stanley 874f2a8f58SJoel Stanley err = aspeed_gfx_set_pixel_fmt(priv, &bpp); 884f2a8f58SJoel Stanley if (err) 894f2a8f58SJoel Stanley return; 904f2a8f58SJoel Stanley 914f2a8f58SJoel Stanley #if 0 924f2a8f58SJoel Stanley /* TODO: we have only been able to test with the 40MHz USB clock. The 934f2a8f58SJoel Stanley * clock is fixed, so we cannot adjust it here. */ 944f2a8f58SJoel Stanley clk_set_rate(priv->pixel_clk, m->crtc_clock * 1000); 954f2a8f58SJoel Stanley #endif 964f2a8f58SJoel Stanley 974f2a8f58SJoel Stanley ctrl1 = readl(priv->base + CRT_CTRL1); 984f2a8f58SJoel Stanley ctrl1 &= ~(CRT_CTRL_INTERLACED | 994f2a8f58SJoel Stanley CRT_CTRL_HSYNC_NEGATIVE | 1004f2a8f58SJoel Stanley CRT_CTRL_VSYNC_NEGATIVE); 1014f2a8f58SJoel Stanley 1024f2a8f58SJoel Stanley if (m->flags & DRM_MODE_FLAG_INTERLACE) 1034f2a8f58SJoel Stanley ctrl1 |= CRT_CTRL_INTERLACED; 1044f2a8f58SJoel Stanley 1054f2a8f58SJoel Stanley if (!(m->flags & DRM_MODE_FLAG_PHSYNC)) 1064f2a8f58SJoel Stanley ctrl1 |= CRT_CTRL_HSYNC_NEGATIVE; 1074f2a8f58SJoel Stanley 1084f2a8f58SJoel Stanley if (!(m->flags & DRM_MODE_FLAG_PVSYNC)) 1094f2a8f58SJoel Stanley ctrl1 |= CRT_CTRL_VSYNC_NEGATIVE; 1104f2a8f58SJoel Stanley 1114f2a8f58SJoel Stanley writel(ctrl1, priv->base + CRT_CTRL1); 1124f2a8f58SJoel Stanley 1134f2a8f58SJoel Stanley /* Horizontal timing */ 1144f2a8f58SJoel Stanley writel(CRT_H_TOTAL(m->htotal - 1) | CRT_H_DE(m->hdisplay - 1), 1154f2a8f58SJoel Stanley priv->base + CRT_HORIZ0); 1164f2a8f58SJoel Stanley writel(CRT_H_RS_START(m->hsync_start - 1) | CRT_H_RS_END(m->hsync_end), 1174f2a8f58SJoel Stanley priv->base + CRT_HORIZ1); 1184f2a8f58SJoel Stanley 1194f2a8f58SJoel Stanley 1204f2a8f58SJoel Stanley /* Vertical timing */ 1214f2a8f58SJoel Stanley writel(CRT_V_TOTAL(m->vtotal - 1) | CRT_V_DE(m->vdisplay - 1), 1224f2a8f58SJoel Stanley priv->base + CRT_VERT0); 1234f2a8f58SJoel Stanley writel(CRT_V_RS_START(m->vsync_start) | CRT_V_RS_END(m->vsync_end), 1244f2a8f58SJoel Stanley priv->base + CRT_VERT1); 1254f2a8f58SJoel Stanley 1264f2a8f58SJoel Stanley /* 1274f2a8f58SJoel Stanley * Display Offset: address difference between consecutive scan lines 1284f2a8f58SJoel Stanley * Terminal Count: memory size of one scan line 1294f2a8f58SJoel Stanley */ 1304f2a8f58SJoel Stanley d_offset = m->hdisplay * bpp / 8; 131bce724faSJoel Stanley t_count = DIV_ROUND_UP(m->hdisplay * bpp, priv->scan_line_max); 132bce724faSJoel Stanley 1334f2a8f58SJoel Stanley writel(CRT_DISP_OFFSET(d_offset) | CRT_TERM_COUNT(t_count), 1344f2a8f58SJoel Stanley priv->base + CRT_OFFSET); 1354f2a8f58SJoel Stanley 1364f2a8f58SJoel Stanley /* 1374f2a8f58SJoel Stanley * Threshold: FIFO thresholds of refill and stop (16 byte chunks 1384f2a8f58SJoel Stanley * per line, rounded up) 1394f2a8f58SJoel Stanley */ 140bce724faSJoel Stanley writel(priv->throd_val, priv->base + CRT_THROD); 1414f2a8f58SJoel Stanley } 1424f2a8f58SJoel Stanley 1434f2a8f58SJoel Stanley static void aspeed_gfx_pipe_enable(struct drm_simple_display_pipe *pipe, 1444f2a8f58SJoel Stanley struct drm_crtc_state *crtc_state, 1454f2a8f58SJoel Stanley struct drm_plane_state *plane_state) 1464f2a8f58SJoel Stanley { 1474f2a8f58SJoel Stanley struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); 1484f2a8f58SJoel Stanley struct drm_crtc *crtc = &pipe->crtc; 1494f2a8f58SJoel Stanley 1504f2a8f58SJoel Stanley aspeed_gfx_crtc_mode_set_nofb(priv); 1514f2a8f58SJoel Stanley aspeed_gfx_enable_controller(priv); 1524f2a8f58SJoel Stanley drm_crtc_vblank_on(crtc); 1534f2a8f58SJoel Stanley } 1544f2a8f58SJoel Stanley 1554f2a8f58SJoel Stanley static void aspeed_gfx_pipe_disable(struct drm_simple_display_pipe *pipe) 1564f2a8f58SJoel Stanley { 1574f2a8f58SJoel Stanley struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); 1584f2a8f58SJoel Stanley struct drm_crtc *crtc = &pipe->crtc; 1594f2a8f58SJoel Stanley 1604f2a8f58SJoel Stanley drm_crtc_vblank_off(crtc); 1614f2a8f58SJoel Stanley aspeed_gfx_disable_controller(priv); 1624f2a8f58SJoel Stanley } 1634f2a8f58SJoel Stanley 1644f2a8f58SJoel Stanley static void aspeed_gfx_pipe_update(struct drm_simple_display_pipe *pipe, 1654f2a8f58SJoel Stanley struct drm_plane_state *plane_state) 1664f2a8f58SJoel Stanley { 1674f2a8f58SJoel Stanley struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); 1684f2a8f58SJoel Stanley struct drm_crtc *crtc = &pipe->crtc; 1694f2a8f58SJoel Stanley struct drm_framebuffer *fb = pipe->plane.state->fb; 1704f2a8f58SJoel Stanley struct drm_pending_vblank_event *event; 1714a83c26aSDanilo Krummrich struct drm_gem_dma_object *gem; 1724f2a8f58SJoel Stanley 1734f2a8f58SJoel Stanley spin_lock_irq(&crtc->dev->event_lock); 1744f2a8f58SJoel Stanley event = crtc->state->event; 1754f2a8f58SJoel Stanley if (event) { 1764f2a8f58SJoel Stanley crtc->state->event = NULL; 1774f2a8f58SJoel Stanley 1784f2a8f58SJoel Stanley if (drm_crtc_vblank_get(crtc) == 0) 1794f2a8f58SJoel Stanley drm_crtc_arm_vblank_event(crtc, event); 1804f2a8f58SJoel Stanley else 1814f2a8f58SJoel Stanley drm_crtc_send_vblank_event(crtc, event); 1824f2a8f58SJoel Stanley } 1834f2a8f58SJoel Stanley spin_unlock_irq(&crtc->dev->event_lock); 1844f2a8f58SJoel Stanley 1854f2a8f58SJoel Stanley if (!fb) 1864f2a8f58SJoel Stanley return; 1874f2a8f58SJoel Stanley 1886bcfe8eaSDanilo Krummrich gem = drm_fb_dma_get_gem_obj(fb, 0); 1894f2a8f58SJoel Stanley if (!gem) 1904f2a8f58SJoel Stanley return; 191*8c30eeccSDanilo Krummrich writel(gem->dma_addr, priv->base + CRT_ADDR); 1924f2a8f58SJoel Stanley } 1934f2a8f58SJoel Stanley 1944f2a8f58SJoel Stanley static int aspeed_gfx_enable_vblank(struct drm_simple_display_pipe *pipe) 1954f2a8f58SJoel Stanley { 1964f2a8f58SJoel Stanley struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); 1974f2a8f58SJoel Stanley u32 reg = readl(priv->base + CRT_CTRL1); 1984f2a8f58SJoel Stanley 1994f2a8f58SJoel Stanley /* Clear pending VBLANK IRQ */ 2004f2a8f58SJoel Stanley writel(reg | CRT_CTRL_VERTICAL_INTR_STS, priv->base + CRT_CTRL1); 2014f2a8f58SJoel Stanley 2024f2a8f58SJoel Stanley reg |= CRT_CTRL_VERTICAL_INTR_EN; 2034f2a8f58SJoel Stanley writel(reg, priv->base + CRT_CTRL1); 2044f2a8f58SJoel Stanley 2054f2a8f58SJoel Stanley return 0; 2064f2a8f58SJoel Stanley } 2074f2a8f58SJoel Stanley 2084f2a8f58SJoel Stanley static void aspeed_gfx_disable_vblank(struct drm_simple_display_pipe *pipe) 2094f2a8f58SJoel Stanley { 2104f2a8f58SJoel Stanley struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); 2114f2a8f58SJoel Stanley u32 reg = readl(priv->base + CRT_CTRL1); 2124f2a8f58SJoel Stanley 2134f2a8f58SJoel Stanley reg &= ~CRT_CTRL_VERTICAL_INTR_EN; 2144f2a8f58SJoel Stanley writel(reg, priv->base + CRT_CTRL1); 2154f2a8f58SJoel Stanley 2164f2a8f58SJoel Stanley /* Clear pending VBLANK IRQ */ 2174f2a8f58SJoel Stanley writel(reg | CRT_CTRL_VERTICAL_INTR_STS, priv->base + CRT_CTRL1); 2184f2a8f58SJoel Stanley } 2194f2a8f58SJoel Stanley 22095cbf02bSNishka Dasgupta static const struct drm_simple_display_pipe_funcs aspeed_gfx_funcs = { 2214f2a8f58SJoel Stanley .enable = aspeed_gfx_pipe_enable, 2224f2a8f58SJoel Stanley .disable = aspeed_gfx_pipe_disable, 2234f2a8f58SJoel Stanley .update = aspeed_gfx_pipe_update, 2244f2a8f58SJoel Stanley .enable_vblank = aspeed_gfx_enable_vblank, 2254f2a8f58SJoel Stanley .disable_vblank = aspeed_gfx_disable_vblank, 2264f2a8f58SJoel Stanley }; 2274f2a8f58SJoel Stanley 2284f2a8f58SJoel Stanley static const uint32_t aspeed_gfx_formats[] = { 2294f2a8f58SJoel Stanley DRM_FORMAT_XRGB8888, 2304f2a8f58SJoel Stanley DRM_FORMAT_RGB565, 2314f2a8f58SJoel Stanley }; 2324f2a8f58SJoel Stanley 2334f2a8f58SJoel Stanley int aspeed_gfx_create_pipe(struct drm_device *drm) 2344f2a8f58SJoel Stanley { 235cd829454SDaniel Vetter struct aspeed_gfx *priv = to_aspeed_gfx(drm); 2364f2a8f58SJoel Stanley 2374f2a8f58SJoel Stanley return drm_simple_display_pipe_init(drm, &priv->pipe, &aspeed_gfx_funcs, 2384f2a8f58SJoel Stanley aspeed_gfx_formats, 2394f2a8f58SJoel Stanley ARRAY_SIZE(aspeed_gfx_formats), 2404f2a8f58SJoel Stanley NULL, 2414f2a8f58SJoel Stanley &priv->connector); 2424f2a8f58SJoel Stanley } 243