0001
0002
0003
0004 #include <linux/clk.h>
0005 #include <linux/reset.h>
0006 #include <linux/regmap.h>
0007
0008 #include <drm/drm_crtc_helper.h>
0009 #include <drm/drm_device.h>
0010 #include <drm/drm_fb_cma_helper.h>
0011 #include <drm/drm_fourcc.h>
0012 #include <drm/drm_framebuffer.h>
0013 #include <drm/drm_gem_atomic_helper.h>
0014 #include <drm/drm_gem_cma_helper.h>
0015 #include <drm/drm_panel.h>
0016 #include <drm/drm_simple_kms_helper.h>
0017 #include <drm/drm_vblank.h>
0018
0019 #include "aspeed_gfx.h"
0020
0021 static struct aspeed_gfx *
0022 drm_pipe_to_aspeed_gfx(struct drm_simple_display_pipe *pipe)
0023 {
0024 return container_of(pipe, struct aspeed_gfx, pipe);
0025 }
0026
0027 static int aspeed_gfx_set_pixel_fmt(struct aspeed_gfx *priv, u32 *bpp)
0028 {
0029 struct drm_crtc *crtc = &priv->pipe.crtc;
0030 struct drm_device *drm = crtc->dev;
0031 const u32 format = crtc->primary->state->fb->format->format;
0032 u32 ctrl1;
0033
0034 ctrl1 = readl(priv->base + CRT_CTRL1);
0035 ctrl1 &= ~CRT_CTRL_COLOR_MASK;
0036
0037 switch (format) {
0038 case DRM_FORMAT_RGB565:
0039 dev_dbg(drm->dev, "Setting up RGB565 mode\n");
0040 ctrl1 |= CRT_CTRL_COLOR_RGB565;
0041 *bpp = 16;
0042 break;
0043 case DRM_FORMAT_XRGB8888:
0044 dev_dbg(drm->dev, "Setting up XRGB8888 mode\n");
0045 ctrl1 |= CRT_CTRL_COLOR_XRGB8888;
0046 *bpp = 32;
0047 break;
0048 default:
0049 dev_err(drm->dev, "Unhandled pixel format %08x\n", format);
0050 return -EINVAL;
0051 }
0052
0053 writel(ctrl1, priv->base + CRT_CTRL1);
0054
0055 return 0;
0056 }
0057
0058 static void aspeed_gfx_enable_controller(struct aspeed_gfx *priv)
0059 {
0060 u32 ctrl1 = readl(priv->base + CRT_CTRL1);
0061 u32 ctrl2 = readl(priv->base + CRT_CTRL2);
0062
0063
0064 regmap_update_bits(priv->scu, priv->dac_reg, BIT(16), BIT(16));
0065
0066 writel(ctrl1 | CRT_CTRL_EN, priv->base + CRT_CTRL1);
0067 writel(ctrl2 | CRT_CTRL_DAC_EN, priv->base + CRT_CTRL2);
0068 }
0069
0070 static void aspeed_gfx_disable_controller(struct aspeed_gfx *priv)
0071 {
0072 u32 ctrl1 = readl(priv->base + CRT_CTRL1);
0073 u32 ctrl2 = readl(priv->base + CRT_CTRL2);
0074
0075 writel(ctrl1 & ~CRT_CTRL_EN, priv->base + CRT_CTRL1);
0076 writel(ctrl2 & ~CRT_CTRL_DAC_EN, priv->base + CRT_CTRL2);
0077
0078 regmap_update_bits(priv->scu, priv->dac_reg, BIT(16), 0);
0079 }
0080
0081 static void aspeed_gfx_crtc_mode_set_nofb(struct aspeed_gfx *priv)
0082 {
0083 struct drm_display_mode *m = &priv->pipe.crtc.state->adjusted_mode;
0084 u32 ctrl1, d_offset, t_count, bpp;
0085 int err;
0086
0087 err = aspeed_gfx_set_pixel_fmt(priv, &bpp);
0088 if (err)
0089 return;
0090
0091 #if 0
0092
0093
0094 clk_set_rate(priv->pixel_clk, m->crtc_clock * 1000);
0095 #endif
0096
0097 ctrl1 = readl(priv->base + CRT_CTRL1);
0098 ctrl1 &= ~(CRT_CTRL_INTERLACED |
0099 CRT_CTRL_HSYNC_NEGATIVE |
0100 CRT_CTRL_VSYNC_NEGATIVE);
0101
0102 if (m->flags & DRM_MODE_FLAG_INTERLACE)
0103 ctrl1 |= CRT_CTRL_INTERLACED;
0104
0105 if (!(m->flags & DRM_MODE_FLAG_PHSYNC))
0106 ctrl1 |= CRT_CTRL_HSYNC_NEGATIVE;
0107
0108 if (!(m->flags & DRM_MODE_FLAG_PVSYNC))
0109 ctrl1 |= CRT_CTRL_VSYNC_NEGATIVE;
0110
0111 writel(ctrl1, priv->base + CRT_CTRL1);
0112
0113
0114 writel(CRT_H_TOTAL(m->htotal - 1) | CRT_H_DE(m->hdisplay - 1),
0115 priv->base + CRT_HORIZ0);
0116 writel(CRT_H_RS_START(m->hsync_start - 1) | CRT_H_RS_END(m->hsync_end),
0117 priv->base + CRT_HORIZ1);
0118
0119
0120
0121 writel(CRT_V_TOTAL(m->vtotal - 1) | CRT_V_DE(m->vdisplay - 1),
0122 priv->base + CRT_VERT0);
0123 writel(CRT_V_RS_START(m->vsync_start) | CRT_V_RS_END(m->vsync_end),
0124 priv->base + CRT_VERT1);
0125
0126
0127
0128
0129
0130 d_offset = m->hdisplay * bpp / 8;
0131 t_count = DIV_ROUND_UP(m->hdisplay * bpp, priv->scan_line_max);
0132
0133 writel(CRT_DISP_OFFSET(d_offset) | CRT_TERM_COUNT(t_count),
0134 priv->base + CRT_OFFSET);
0135
0136
0137
0138
0139
0140 writel(priv->throd_val, priv->base + CRT_THROD);
0141 }
0142
0143 static void aspeed_gfx_pipe_enable(struct drm_simple_display_pipe *pipe,
0144 struct drm_crtc_state *crtc_state,
0145 struct drm_plane_state *plane_state)
0146 {
0147 struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe);
0148 struct drm_crtc *crtc = &pipe->crtc;
0149
0150 aspeed_gfx_crtc_mode_set_nofb(priv);
0151 aspeed_gfx_enable_controller(priv);
0152 drm_crtc_vblank_on(crtc);
0153 }
0154
0155 static void aspeed_gfx_pipe_disable(struct drm_simple_display_pipe *pipe)
0156 {
0157 struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe);
0158 struct drm_crtc *crtc = &pipe->crtc;
0159
0160 drm_crtc_vblank_off(crtc);
0161 aspeed_gfx_disable_controller(priv);
0162 }
0163
0164 static void aspeed_gfx_pipe_update(struct drm_simple_display_pipe *pipe,
0165 struct drm_plane_state *plane_state)
0166 {
0167 struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe);
0168 struct drm_crtc *crtc = &pipe->crtc;
0169 struct drm_framebuffer *fb = pipe->plane.state->fb;
0170 struct drm_pending_vblank_event *event;
0171 struct drm_gem_cma_object *gem;
0172
0173 spin_lock_irq(&crtc->dev->event_lock);
0174 event = crtc->state->event;
0175 if (event) {
0176 crtc->state->event = NULL;
0177
0178 if (drm_crtc_vblank_get(crtc) == 0)
0179 drm_crtc_arm_vblank_event(crtc, event);
0180 else
0181 drm_crtc_send_vblank_event(crtc, event);
0182 }
0183 spin_unlock_irq(&crtc->dev->event_lock);
0184
0185 if (!fb)
0186 return;
0187
0188 gem = drm_fb_cma_get_gem_obj(fb, 0);
0189 if (!gem)
0190 return;
0191 writel(gem->paddr, priv->base + CRT_ADDR);
0192 }
0193
0194 static int aspeed_gfx_enable_vblank(struct drm_simple_display_pipe *pipe)
0195 {
0196 struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe);
0197 u32 reg = readl(priv->base + CRT_CTRL1);
0198
0199
0200 writel(reg | CRT_CTRL_VERTICAL_INTR_STS, priv->base + CRT_CTRL1);
0201
0202 reg |= CRT_CTRL_VERTICAL_INTR_EN;
0203 writel(reg, priv->base + CRT_CTRL1);
0204
0205 return 0;
0206 }
0207
0208 static void aspeed_gfx_disable_vblank(struct drm_simple_display_pipe *pipe)
0209 {
0210 struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe);
0211 u32 reg = readl(priv->base + CRT_CTRL1);
0212
0213 reg &= ~CRT_CTRL_VERTICAL_INTR_EN;
0214 writel(reg, priv->base + CRT_CTRL1);
0215
0216
0217 writel(reg | CRT_CTRL_VERTICAL_INTR_STS, priv->base + CRT_CTRL1);
0218 }
0219
0220 static const struct drm_simple_display_pipe_funcs aspeed_gfx_funcs = {
0221 .enable = aspeed_gfx_pipe_enable,
0222 .disable = aspeed_gfx_pipe_disable,
0223 .update = aspeed_gfx_pipe_update,
0224 .enable_vblank = aspeed_gfx_enable_vblank,
0225 .disable_vblank = aspeed_gfx_disable_vblank,
0226 };
0227
0228 static const uint32_t aspeed_gfx_formats[] = {
0229 DRM_FORMAT_XRGB8888,
0230 DRM_FORMAT_RGB565,
0231 };
0232
0233 int aspeed_gfx_create_pipe(struct drm_device *drm)
0234 {
0235 struct aspeed_gfx *priv = to_aspeed_gfx(drm);
0236
0237 return drm_simple_display_pipe_init(drm, &priv->pipe, &aspeed_gfx_funcs,
0238 aspeed_gfx_formats,
0239 ARRAY_SIZE(aspeed_gfx_formats),
0240 NULL,
0241 &priv->connector);
0242 }