1 // SPDX-License-Identifier: GPL-2.0+
2 // Copyright 2018 IBM Corporation
5 #include <linux/dma-mapping.h>
7 #include <linux/mfd/syscon.h>
8 #include <linux/module.h>
10 #include <linux/of_reserved_mem.h>
11 #include <linux/platform_device.h>
12 #include <linux/regmap.h>
13 #include <linux/reset.h>
15 #include <drm/drm_atomic_helper.h>
16 #include <drm/drm_crtc_helper.h>
17 #include <drm/drm_device.h>
18 #include <drm/drm_fb_cma_helper.h>
19 #include <drm/drm_fb_helper.h>
20 #include <drm/drm_gem_cma_helper.h>
21 #include <drm/drm_gem_framebuffer_helper.h>
22 #include <drm/drm_probe_helper.h>
23 #include <drm/drm_simple_kms_helper.h>
24 #include <drm/drm_vblank.h>
25 #include <drm/drm_drv.h>
27 #include "aspeed_gfx.h"
30 * DOC: ASPEED GFX Driver
32 * This driver is for the ASPEED BMC SoC's 'GFX' display hardware, also called
33 * the 'SOC Display Controller' in the datasheet. This driver runs on the ARM
34 * based BMC systems, unlike the ast driver which runs on a host CPU and is for
35 * a PCIe graphics device.
37 * The AST2500 supports a total of 3 output paths:
39 * 1. VGA output, the output target can choose either or both to the DAC
42 * 2. Graphics CRT output, the output target can choose either or both to
43 * the DAC or DVO interface.
45 * 3. Video input from DVO, the video input can be used for video engine
46 * capture or DAC display output.
48 * Output options are selected in SCU2C.
50 * The "VGA mode" device is the PCI attached controller. The "Graphics CRT"
51 * is the ARM's internal display controller.
53 * The driver only supports a simple configuration consisting of a 40MHz
54 * pixel clock, fixed by hardware limitations, and the VGA output path.
56 * The driver was written with the 'AST2500 Software Programming Guide' v17,
57 * which is available under NDA from ASPEED.
60 static const struct drm_mode_config_funcs aspeed_gfx_mode_config_funcs
= {
61 .fb_create
= drm_gem_fb_create
,
62 .atomic_check
= drm_atomic_helper_check
,
63 .atomic_commit
= drm_atomic_helper_commit
,
66 static void aspeed_gfx_setup_mode_config(struct drm_device
*drm
)
68 drm_mode_config_init(drm
);
70 drm
->mode_config
.min_width
= 0;
71 drm
->mode_config
.min_height
= 0;
72 drm
->mode_config
.max_width
= 800;
73 drm
->mode_config
.max_height
= 600;
74 drm
->mode_config
.funcs
= &aspeed_gfx_mode_config_funcs
;
77 static irqreturn_t
aspeed_gfx_irq_handler(int irq
, void *data
)
79 struct drm_device
*drm
= data
;
80 struct aspeed_gfx
*priv
= drm
->dev_private
;
83 reg
= readl(priv
->base
+ CRT_CTRL1
);
85 if (reg
& CRT_CTRL_VERTICAL_INTR_STS
) {
86 drm_crtc_handle_vblank(&priv
->pipe
.crtc
);
87 writel(reg
, priv
->base
+ CRT_CTRL1
);
96 static int aspeed_gfx_load(struct drm_device
*drm
)
98 struct platform_device
*pdev
= to_platform_device(drm
->dev
);
99 struct aspeed_gfx
*priv
;
100 struct resource
*res
;
103 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
106 drm
->dev_private
= priv
;
108 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
109 priv
->base
= devm_ioremap_resource(drm
->dev
, res
);
110 if (IS_ERR(priv
->base
))
111 return PTR_ERR(priv
->base
);
113 priv
->scu
= syscon_regmap_lookup_by_compatible("aspeed,ast2500-scu");
114 if (IS_ERR(priv
->scu
)) {
115 dev_err(&pdev
->dev
, "failed to find SCU regmap\n");
116 return PTR_ERR(priv
->scu
);
119 ret
= of_reserved_mem_device_init(drm
->dev
);
122 "failed to initialize reserved mem: %d\n", ret
);
126 ret
= dma_set_mask_and_coherent(drm
->dev
, DMA_BIT_MASK(32));
128 dev_err(&pdev
->dev
, "failed to set DMA mask: %d\n", ret
);
132 priv
->rst
= devm_reset_control_get_exclusive(&pdev
->dev
, NULL
);
133 if (IS_ERR(priv
->rst
)) {
135 "missing or invalid reset controller device tree entry");
136 return PTR_ERR(priv
->rst
);
138 reset_control_deassert(priv
->rst
);
140 priv
->clk
= devm_clk_get(drm
->dev
, NULL
);
141 if (IS_ERR(priv
->clk
)) {
143 "missing or invalid clk device tree entry");
144 return PTR_ERR(priv
->clk
);
146 clk_prepare_enable(priv
->clk
);
148 /* Sanitize control registers */
149 writel(0, priv
->base
+ CRT_CTRL1
);
150 writel(0, priv
->base
+ CRT_CTRL2
);
152 aspeed_gfx_setup_mode_config(drm
);
154 ret
= drm_vblank_init(drm
, 1);
156 dev_err(drm
->dev
, "Failed to initialise vblank\n");
160 ret
= aspeed_gfx_create_output(drm
);
162 dev_err(drm
->dev
, "Failed to create outputs\n");
166 ret
= aspeed_gfx_create_pipe(drm
);
168 dev_err(drm
->dev
, "Cannot setup simple display pipe\n");
172 ret
= devm_request_irq(drm
->dev
, platform_get_irq(pdev
, 0),
173 aspeed_gfx_irq_handler
, 0, "aspeed gfx", drm
);
175 dev_err(drm
->dev
, "Failed to install IRQ handler\n");
179 drm_mode_config_reset(drm
);
181 drm_fbdev_generic_setup(drm
, 32);
186 static void aspeed_gfx_unload(struct drm_device
*drm
)
188 drm_kms_helper_poll_fini(drm
);
189 drm_mode_config_cleanup(drm
);
191 drm
->dev_private
= NULL
;
194 DEFINE_DRM_GEM_CMA_FOPS(fops
);
196 static struct drm_driver aspeed_gfx_driver
= {
197 .driver_features
= DRIVER_GEM
| DRIVER_MODESET
| DRIVER_ATOMIC
,
198 .gem_create_object
= drm_cma_gem_create_object_default_funcs
,
199 .dumb_create
= drm_gem_cma_dumb_create
,
200 .prime_handle_to_fd
= drm_gem_prime_handle_to_fd
,
201 .prime_fd_to_handle
= drm_gem_prime_fd_to_handle
,
202 .gem_prime_import_sg_table
= drm_gem_cma_prime_import_sg_table
,
203 .gem_prime_mmap
= drm_gem_prime_mmap
,
205 .name
= "aspeed-gfx-drm",
206 .desc
= "ASPEED GFX DRM",
212 static const struct of_device_id aspeed_gfx_match
[] = {
213 { .compatible
= "aspeed,ast2500-gfx" },
217 static int aspeed_gfx_probe(struct platform_device
*pdev
)
219 struct drm_device
*drm
;
222 drm
= drm_dev_alloc(&aspeed_gfx_driver
, &pdev
->dev
);
226 ret
= aspeed_gfx_load(drm
);
230 ret
= drm_dev_register(drm
, 0);
237 aspeed_gfx_unload(drm
);
244 static int aspeed_gfx_remove(struct platform_device
*pdev
)
246 struct drm_device
*drm
= platform_get_drvdata(pdev
);
248 drm_dev_unregister(drm
);
249 aspeed_gfx_unload(drm
);
255 static struct platform_driver aspeed_gfx_platform_driver
= {
256 .probe
= aspeed_gfx_probe
,
257 .remove
= aspeed_gfx_remove
,
259 .name
= "aspeed_gfx",
260 .of_match_table
= aspeed_gfx_match
,
264 module_platform_driver(aspeed_gfx_platform_driver
);
266 MODULE_AUTHOR("Joel Stanley <joel@jms.id.au>");
267 MODULE_DESCRIPTION("ASPEED BMC DRM/KMS driver");
268 MODULE_LICENSE("GPL");