4 * Copyright (C) 2016 Synopsys, Inc. (www.synopsys.com)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
17 #include <linux/clk.h>
18 #include <drm/drm_crtc_helper.h>
19 #include <drm/drm_fb_cma_helper.h>
20 #include <drm/drm_gem_cma_helper.h>
21 #include <drm/drm_gem_framebuffer_helper.h>
22 #include <drm/drm_atomic_helper.h>
23 #include <linux/of_reserved_mem.h>
26 #include "arcpgu_regs.h"
28 static void arcpgu_fb_output_poll_changed(struct drm_device
*dev
)
30 struct arcpgu_drm_private
*arcpgu
= dev
->dev_private
;
32 drm_fbdev_cma_hotplug_event(arcpgu
->fbdev
);
35 static const struct drm_mode_config_funcs arcpgu_drm_modecfg_funcs
= {
36 .fb_create
= drm_gem_fb_create
,
37 .output_poll_changed
= arcpgu_fb_output_poll_changed
,
38 .atomic_check
= drm_atomic_helper_check
,
39 .atomic_commit
= drm_atomic_helper_commit
,
42 static void arcpgu_setup_mode_config(struct drm_device
*drm
)
44 drm_mode_config_init(drm
);
45 drm
->mode_config
.min_width
= 0;
46 drm
->mode_config
.min_height
= 0;
47 drm
->mode_config
.max_width
= 1920;
48 drm
->mode_config
.max_height
= 1080;
49 drm
->mode_config
.funcs
= &arcpgu_drm_modecfg_funcs
;
52 DEFINE_DRM_GEM_CMA_FOPS(arcpgu_drm_ops
);
54 static void arcpgu_lastclose(struct drm_device
*drm
)
56 struct arcpgu_drm_private
*arcpgu
= drm
->dev_private
;
58 drm_fbdev_cma_restore_mode(arcpgu
->fbdev
);
61 static int arcpgu_load(struct drm_device
*drm
)
63 struct platform_device
*pdev
= to_platform_device(drm
->dev
);
64 struct arcpgu_drm_private
*arcpgu
;
65 struct device_node
*encoder_node
;
69 arcpgu
= devm_kzalloc(&pdev
->dev
, sizeof(*arcpgu
), GFP_KERNEL
);
73 drm
->dev_private
= arcpgu
;
75 arcpgu
->clk
= devm_clk_get(drm
->dev
, "pxlclk");
76 if (IS_ERR(arcpgu
->clk
))
77 return PTR_ERR(arcpgu
->clk
);
79 arcpgu_setup_mode_config(drm
);
81 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
82 arcpgu
->regs
= devm_ioremap_resource(&pdev
->dev
, res
);
83 if (IS_ERR(arcpgu
->regs
))
84 return PTR_ERR(arcpgu
->regs
);
86 dev_info(drm
->dev
, "arc_pgu ID: 0x%x\n",
87 arc_pgu_read(arcpgu
, ARCPGU_REG_ID
));
89 /* Get the optional framebuffer memory resource */
90 ret
= of_reserved_mem_device_init(drm
->dev
);
91 if (ret
&& ret
!= -ENODEV
)
94 if (dma_set_mask_and_coherent(drm
->dev
, DMA_BIT_MASK(32)))
97 if (arc_pgu_setup_crtc(drm
) < 0)
100 /* find the encoder node and initialize it */
101 encoder_node
= of_parse_phandle(drm
->dev
->of_node
, "encoder-slave", 0);
103 ret
= arcpgu_drm_hdmi_init(drm
, encoder_node
);
104 of_node_put(encoder_node
);
108 ret
= arcpgu_drm_sim_init(drm
, NULL
);
113 drm_mode_config_reset(drm
);
114 drm_kms_helper_poll_init(drm
);
116 arcpgu
->fbdev
= drm_fbdev_cma_init(drm
, 16,
117 drm
->mode_config
.num_connector
);
118 if (IS_ERR(arcpgu
->fbdev
)) {
119 ret
= PTR_ERR(arcpgu
->fbdev
);
120 arcpgu
->fbdev
= NULL
;
124 platform_set_drvdata(pdev
, drm
);
128 static int arcpgu_unload(struct drm_device
*drm
)
130 struct arcpgu_drm_private
*arcpgu
= drm
->dev_private
;
133 drm_fbdev_cma_fini(arcpgu
->fbdev
);
134 arcpgu
->fbdev
= NULL
;
136 drm_kms_helper_poll_fini(drm
);
137 drm_mode_config_cleanup(drm
);
142 #ifdef CONFIG_DEBUG_FS
143 static int arcpgu_show_pxlclock(struct seq_file
*m
, void *arg
)
145 struct drm_info_node
*node
= (struct drm_info_node
*)m
->private;
146 struct drm_device
*drm
= node
->minor
->dev
;
147 struct arcpgu_drm_private
*arcpgu
= drm
->dev_private
;
148 unsigned long clkrate
= clk_get_rate(arcpgu
->clk
);
149 unsigned long mode_clock
= arcpgu
->crtc
.mode
.crtc_clock
* 1000;
151 seq_printf(m
, "hw : %lu\n", clkrate
);
152 seq_printf(m
, "mode: %lu\n", mode_clock
);
156 static struct drm_info_list arcpgu_debugfs_list
[] = {
157 { "clocks", arcpgu_show_pxlclock
, 0 },
160 static int arcpgu_debugfs_init(struct drm_minor
*minor
)
162 return drm_debugfs_create_files(arcpgu_debugfs_list
,
163 ARRAY_SIZE(arcpgu_debugfs_list
), minor
->debugfs_root
, minor
);
167 static struct drm_driver arcpgu_drm_driver
= {
168 .driver_features
= DRIVER_MODESET
| DRIVER_GEM
| DRIVER_PRIME
|
170 .lastclose
= arcpgu_lastclose
,
172 .desc
= "ARC PGU Controller",
177 .fops
= &arcpgu_drm_ops
,
178 .dumb_create
= drm_gem_cma_dumb_create
,
179 .prime_handle_to_fd
= drm_gem_prime_handle_to_fd
,
180 .prime_fd_to_handle
= drm_gem_prime_fd_to_handle
,
181 .gem_free_object_unlocked
= drm_gem_cma_free_object
,
182 .gem_print_info
= drm_gem_cma_print_info
,
183 .gem_vm_ops
= &drm_gem_cma_vm_ops
,
184 .gem_prime_export
= drm_gem_prime_export
,
185 .gem_prime_import
= drm_gem_prime_import
,
186 .gem_prime_get_sg_table
= drm_gem_cma_prime_get_sg_table
,
187 .gem_prime_import_sg_table
= drm_gem_cma_prime_import_sg_table
,
188 .gem_prime_vmap
= drm_gem_cma_prime_vmap
,
189 .gem_prime_vunmap
= drm_gem_cma_prime_vunmap
,
190 .gem_prime_mmap
= drm_gem_cma_prime_mmap
,
191 #ifdef CONFIG_DEBUG_FS
192 .debugfs_init
= arcpgu_debugfs_init
,
196 static int arcpgu_probe(struct platform_device
*pdev
)
198 struct drm_device
*drm
;
201 drm
= drm_dev_alloc(&arcpgu_drm_driver
, &pdev
->dev
);
205 ret
= arcpgu_load(drm
);
209 ret
= drm_dev_register(drm
, 0);
224 static int arcpgu_remove(struct platform_device
*pdev
)
226 struct drm_device
*drm
= platform_get_drvdata(pdev
);
228 drm_dev_unregister(drm
);
235 static const struct of_device_id arcpgu_of_table
[] = {
236 {.compatible
= "snps,arcpgu"},
240 MODULE_DEVICE_TABLE(of
, arcpgu_of_table
);
242 static struct platform_driver arcpgu_platform_driver
= {
243 .probe
= arcpgu_probe
,
244 .remove
= arcpgu_remove
,
247 .of_match_table
= arcpgu_of_table
,
251 module_platform_driver(arcpgu_platform_driver
);
253 MODULE_AUTHOR("Carlos Palminha <palminha@synopsys.com>");
254 MODULE_DESCRIPTION("ARC PGU DRM driver");
255 MODULE_LICENSE("GPL");