1 // SPDX-License-Identifier: GPL-2.0+
2 // Copyright 2018 IBM Corporation
5 #include <linux/reset.h>
6 #include <linux/regmap.h>
8 #include <drm/drm_crtc_helper.h>
9 #include <drm/drm_device.h>
10 #include <drm/drm_fb_cma_helper.h>
11 #include <drm/drm_fourcc.h>
12 #include <drm/drm_gem_cma_helper.h>
13 #include <drm/drm_gem_framebuffer_helper.h>
14 #include <drm/drm_panel.h>
15 #include <drm/drm_simple_kms_helper.h>
16 #include <drm/drm_vblank.h>
18 #include "aspeed_gfx.h"
20 static struct aspeed_gfx
*
21 drm_pipe_to_aspeed_gfx(struct drm_simple_display_pipe
*pipe
)
23 return container_of(pipe
, struct aspeed_gfx
, pipe
);
26 static int aspeed_gfx_set_pixel_fmt(struct aspeed_gfx
*priv
, u32
*bpp
)
28 struct drm_crtc
*crtc
= &priv
->pipe
.crtc
;
29 struct drm_device
*drm
= crtc
->dev
;
30 const u32 format
= crtc
->primary
->state
->fb
->format
->format
;
33 ctrl1
= readl(priv
->base
+ CRT_CTRL1
);
34 ctrl1
&= ~CRT_CTRL_COLOR_MASK
;
37 case DRM_FORMAT_RGB565
:
38 dev_dbg(drm
->dev
, "Setting up RGB565 mode\n");
39 ctrl1
|= CRT_CTRL_COLOR_RGB565
;
42 case DRM_FORMAT_XRGB8888
:
43 dev_dbg(drm
->dev
, "Setting up XRGB8888 mode\n");
44 ctrl1
|= CRT_CTRL_COLOR_XRGB8888
;
48 dev_err(drm
->dev
, "Unhandled pixel format %08x\n", format
);
52 writel(ctrl1
, priv
->base
+ CRT_CTRL1
);
57 static void aspeed_gfx_enable_controller(struct aspeed_gfx
*priv
)
59 u32 ctrl1
= readl(priv
->base
+ CRT_CTRL1
);
60 u32 ctrl2
= readl(priv
->base
+ CRT_CTRL2
);
62 /* SCU2C: set DAC source for display output to Graphics CRT (GFX) */
63 regmap_update_bits(priv
->scu
, 0x2c, BIT(16), BIT(16));
65 writel(ctrl1
| CRT_CTRL_EN
, priv
->base
+ CRT_CTRL1
);
66 writel(ctrl2
| CRT_CTRL_DAC_EN
, priv
->base
+ CRT_CTRL2
);
69 static void aspeed_gfx_disable_controller(struct aspeed_gfx
*priv
)
71 u32 ctrl1
= readl(priv
->base
+ CRT_CTRL1
);
72 u32 ctrl2
= readl(priv
->base
+ CRT_CTRL2
);
74 writel(ctrl1
& ~CRT_CTRL_EN
, priv
->base
+ CRT_CTRL1
);
75 writel(ctrl2
& ~CRT_CTRL_DAC_EN
, priv
->base
+ CRT_CTRL2
);
77 regmap_update_bits(priv
->scu
, 0x2c, BIT(16), 0);
80 static void aspeed_gfx_crtc_mode_set_nofb(struct aspeed_gfx
*priv
)
82 struct drm_display_mode
*m
= &priv
->pipe
.crtc
.state
->adjusted_mode
;
83 u32 ctrl1
, d_offset
, t_count
, bpp
;
86 err
= aspeed_gfx_set_pixel_fmt(priv
, &bpp
);
91 /* TODO: we have only been able to test with the 40MHz USB clock. The
92 * clock is fixed, so we cannot adjust it here. */
93 clk_set_rate(priv
->pixel_clk
, m
->crtc_clock
* 1000);
96 ctrl1
= readl(priv
->base
+ CRT_CTRL1
);
97 ctrl1
&= ~(CRT_CTRL_INTERLACED
|
98 CRT_CTRL_HSYNC_NEGATIVE
|
99 CRT_CTRL_VSYNC_NEGATIVE
);
101 if (m
->flags
& DRM_MODE_FLAG_INTERLACE
)
102 ctrl1
|= CRT_CTRL_INTERLACED
;
104 if (!(m
->flags
& DRM_MODE_FLAG_PHSYNC
))
105 ctrl1
|= CRT_CTRL_HSYNC_NEGATIVE
;
107 if (!(m
->flags
& DRM_MODE_FLAG_PVSYNC
))
108 ctrl1
|= CRT_CTRL_VSYNC_NEGATIVE
;
110 writel(ctrl1
, priv
->base
+ CRT_CTRL1
);
112 /* Horizontal timing */
113 writel(CRT_H_TOTAL(m
->htotal
- 1) | CRT_H_DE(m
->hdisplay
- 1),
114 priv
->base
+ CRT_HORIZ0
);
115 writel(CRT_H_RS_START(m
->hsync_start
- 1) | CRT_H_RS_END(m
->hsync_end
),
116 priv
->base
+ CRT_HORIZ1
);
119 /* Vertical timing */
120 writel(CRT_V_TOTAL(m
->vtotal
- 1) | CRT_V_DE(m
->vdisplay
- 1),
121 priv
->base
+ CRT_VERT0
);
122 writel(CRT_V_RS_START(m
->vsync_start
) | CRT_V_RS_END(m
->vsync_end
),
123 priv
->base
+ CRT_VERT1
);
126 * Display Offset: address difference between consecutive scan lines
127 * Terminal Count: memory size of one scan line
129 d_offset
= m
->hdisplay
* bpp
/ 8;
130 t_count
= (m
->hdisplay
* bpp
+ 127) / 128;
131 writel(CRT_DISP_OFFSET(d_offset
) | CRT_TERM_COUNT(t_count
),
132 priv
->base
+ CRT_OFFSET
);
135 * Threshold: FIFO thresholds of refill and stop (16 byte chunks
136 * per line, rounded up)
138 writel(G5_CRT_THROD_VAL
, priv
->base
+ CRT_THROD
);
141 static void aspeed_gfx_pipe_enable(struct drm_simple_display_pipe
*pipe
,
142 struct drm_crtc_state
*crtc_state
,
143 struct drm_plane_state
*plane_state
)
145 struct aspeed_gfx
*priv
= drm_pipe_to_aspeed_gfx(pipe
);
146 struct drm_crtc
*crtc
= &pipe
->crtc
;
148 aspeed_gfx_crtc_mode_set_nofb(priv
);
149 aspeed_gfx_enable_controller(priv
);
150 drm_crtc_vblank_on(crtc
);
153 static void aspeed_gfx_pipe_disable(struct drm_simple_display_pipe
*pipe
)
155 struct aspeed_gfx
*priv
= drm_pipe_to_aspeed_gfx(pipe
);
156 struct drm_crtc
*crtc
= &pipe
->crtc
;
158 drm_crtc_vblank_off(crtc
);
159 aspeed_gfx_disable_controller(priv
);
162 static void aspeed_gfx_pipe_update(struct drm_simple_display_pipe
*pipe
,
163 struct drm_plane_state
*plane_state
)
165 struct aspeed_gfx
*priv
= drm_pipe_to_aspeed_gfx(pipe
);
166 struct drm_crtc
*crtc
= &pipe
->crtc
;
167 struct drm_framebuffer
*fb
= pipe
->plane
.state
->fb
;
168 struct drm_pending_vblank_event
*event
;
169 struct drm_gem_cma_object
*gem
;
171 spin_lock_irq(&crtc
->dev
->event_lock
);
172 event
= crtc
->state
->event
;
174 crtc
->state
->event
= NULL
;
176 if (drm_crtc_vblank_get(crtc
) == 0)
177 drm_crtc_arm_vblank_event(crtc
, event
);
179 drm_crtc_send_vblank_event(crtc
, event
);
181 spin_unlock_irq(&crtc
->dev
->event_lock
);
186 gem
= drm_fb_cma_get_gem_obj(fb
, 0);
189 writel(gem
->paddr
, priv
->base
+ CRT_ADDR
);
192 static int aspeed_gfx_enable_vblank(struct drm_simple_display_pipe
*pipe
)
194 struct aspeed_gfx
*priv
= drm_pipe_to_aspeed_gfx(pipe
);
195 u32 reg
= readl(priv
->base
+ CRT_CTRL1
);
197 /* Clear pending VBLANK IRQ */
198 writel(reg
| CRT_CTRL_VERTICAL_INTR_STS
, priv
->base
+ CRT_CTRL1
);
200 reg
|= CRT_CTRL_VERTICAL_INTR_EN
;
201 writel(reg
, priv
->base
+ CRT_CTRL1
);
206 static void aspeed_gfx_disable_vblank(struct drm_simple_display_pipe
*pipe
)
208 struct aspeed_gfx
*priv
= drm_pipe_to_aspeed_gfx(pipe
);
209 u32 reg
= readl(priv
->base
+ CRT_CTRL1
);
211 reg
&= ~CRT_CTRL_VERTICAL_INTR_EN
;
212 writel(reg
, priv
->base
+ CRT_CTRL1
);
214 /* Clear pending VBLANK IRQ */
215 writel(reg
| CRT_CTRL_VERTICAL_INTR_STS
, priv
->base
+ CRT_CTRL1
);
218 static const struct drm_simple_display_pipe_funcs aspeed_gfx_funcs
= {
219 .enable
= aspeed_gfx_pipe_enable
,
220 .disable
= aspeed_gfx_pipe_disable
,
221 .update
= aspeed_gfx_pipe_update
,
222 .prepare_fb
= drm_gem_fb_simple_display_pipe_prepare_fb
,
223 .enable_vblank
= aspeed_gfx_enable_vblank
,
224 .disable_vblank
= aspeed_gfx_disable_vblank
,
227 static const uint32_t aspeed_gfx_formats
[] = {
232 int aspeed_gfx_create_pipe(struct drm_device
*drm
)
234 struct aspeed_gfx
*priv
= to_aspeed_gfx(drm
);
236 return drm_simple_display_pipe_init(drm
, &priv
->pipe
, &aspeed_gfx_funcs
,
238 ARRAY_SIZE(aspeed_gfx_formats
),