1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * linux/drivers/video/wmt_ge_rops.c |
4 | * |
5 | * Accelerators for raster operations using WonderMedia Graphics Engine |
6 | * |
7 | * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> |
8 | */ |
9 | |
10 | #include <linux/module.h> |
11 | #include <linux/fb.h> |
12 | #include <linux/io.h> |
13 | #include <linux/platform_device.h> |
14 | |
15 | #include "core/fb_draw.h" |
16 | #include "wmt_ge_rops.h" |
17 | |
18 | #define GE_COMMAND_OFF 0x00 |
19 | #define GE_DEPTH_OFF 0x04 |
20 | #define GE_HIGHCOLOR_OFF 0x08 |
21 | #define GE_ROPCODE_OFF 0x14 |
22 | #define GE_FIRE_OFF 0x18 |
23 | #define GE_SRCBASE_OFF 0x20 |
24 | #define GE_SRCDISPW_OFF 0x24 |
25 | #define GE_SRCDISPH_OFF 0x28 |
26 | #define GE_SRCAREAX_OFF 0x2c |
27 | #define GE_SRCAREAY_OFF 0x30 |
28 | #define GE_SRCAREAW_OFF 0x34 |
29 | #define GE_SRCAREAH_OFF 0x38 |
30 | #define GE_DESTBASE_OFF 0x3c |
31 | #define GE_DESTDISPW_OFF 0x40 |
32 | #define GE_DESTDISPH_OFF 0x44 |
33 | #define GE_DESTAREAX_OFF 0x48 |
34 | #define GE_DESTAREAY_OFF 0x4c |
35 | #define GE_DESTAREAW_OFF 0x50 |
36 | #define GE_DESTAREAH_OFF 0x54 |
37 | #define GE_PAT0C_OFF 0x88 /* Pattern 0 color */ |
38 | #define GE_ENABLE_OFF 0xec |
39 | #define GE_INTEN_OFF 0xf0 |
40 | #define GE_STATUS_OFF 0xf8 |
41 | |
42 | static void __iomem *regbase; |
43 | |
44 | void wmt_ge_fillrect(struct fb_info *p, const struct fb_fillrect *rect) |
45 | { |
46 | unsigned long fg, pat; |
47 | |
48 | if (p->state != FBINFO_STATE_RUNNING) |
49 | return; |
50 | |
51 | if (p->fix.visual == FB_VISUAL_TRUECOLOR || |
52 | p->fix.visual == FB_VISUAL_DIRECTCOLOR) |
53 | fg = ((u32 *) (p->pseudo_palette))[rect->color]; |
54 | else |
55 | fg = rect->color; |
56 | |
57 | pat = pixel_to_pat(bpp: p->var.bits_per_pixel, pixel: fg); |
58 | |
59 | if (p->fbops->fb_sync) |
60 | p->fbops->fb_sync(p); |
61 | |
62 | writel(val: p->var.bits_per_pixel == 32 ? 3 : |
63 | (p->var.bits_per_pixel == 8 ? 0 : 1), addr: regbase + GE_DEPTH_OFF); |
64 | writel(val: p->var.bits_per_pixel == 15 ? 1 : 0, addr: regbase + GE_HIGHCOLOR_OFF); |
65 | writel(val: p->fix.smem_start, addr: regbase + GE_DESTBASE_OFF); |
66 | writel(val: p->var.xres_virtual - 1, addr: regbase + GE_DESTDISPW_OFF); |
67 | writel(val: p->var.yres_virtual - 1, addr: regbase + GE_DESTDISPH_OFF); |
68 | writel(val: rect->dx, addr: regbase + GE_DESTAREAX_OFF); |
69 | writel(val: rect->dy, addr: regbase + GE_DESTAREAY_OFF); |
70 | writel(val: rect->width - 1, addr: regbase + GE_DESTAREAW_OFF); |
71 | writel(val: rect->height - 1, addr: regbase + GE_DESTAREAH_OFF); |
72 | |
73 | writel(val: pat, addr: regbase + GE_PAT0C_OFF); |
74 | writel(val: 1, addr: regbase + GE_COMMAND_OFF); |
75 | writel(val: rect->rop == ROP_XOR ? 0x5a : 0xf0, addr: regbase + GE_ROPCODE_OFF); |
76 | writel(val: 1, addr: regbase + GE_FIRE_OFF); |
77 | } |
78 | EXPORT_SYMBOL_GPL(wmt_ge_fillrect); |
79 | |
80 | void wmt_ge_copyarea(struct fb_info *p, const struct fb_copyarea *area) |
81 | { |
82 | if (p->state != FBINFO_STATE_RUNNING) |
83 | return; |
84 | |
85 | if (p->fbops->fb_sync) |
86 | p->fbops->fb_sync(p); |
87 | |
88 | writel(val: p->var.bits_per_pixel > 16 ? 3 : |
89 | (p->var.bits_per_pixel > 8 ? 1 : 0), addr: regbase + GE_DEPTH_OFF); |
90 | |
91 | writel(val: p->fix.smem_start, addr: regbase + GE_SRCBASE_OFF); |
92 | writel(val: p->var.xres_virtual - 1, addr: regbase + GE_SRCDISPW_OFF); |
93 | writel(val: p->var.yres_virtual - 1, addr: regbase + GE_SRCDISPH_OFF); |
94 | writel(val: area->sx, addr: regbase + GE_SRCAREAX_OFF); |
95 | writel(val: area->sy, addr: regbase + GE_SRCAREAY_OFF); |
96 | writel(val: area->width - 1, addr: regbase + GE_SRCAREAW_OFF); |
97 | writel(val: area->height - 1, addr: regbase + GE_SRCAREAH_OFF); |
98 | |
99 | writel(val: p->fix.smem_start, addr: regbase + GE_DESTBASE_OFF); |
100 | writel(val: p->var.xres_virtual - 1, addr: regbase + GE_DESTDISPW_OFF); |
101 | writel(val: p->var.yres_virtual - 1, addr: regbase + GE_DESTDISPH_OFF); |
102 | writel(val: area->dx, addr: regbase + GE_DESTAREAX_OFF); |
103 | writel(val: area->dy, addr: regbase + GE_DESTAREAY_OFF); |
104 | writel(val: area->width - 1, addr: regbase + GE_DESTAREAW_OFF); |
105 | writel(val: area->height - 1, addr: regbase + GE_DESTAREAH_OFF); |
106 | |
107 | writel(val: 0xcc, addr: regbase + GE_ROPCODE_OFF); |
108 | writel(val: 1, addr: regbase + GE_COMMAND_OFF); |
109 | writel(val: 1, addr: regbase + GE_FIRE_OFF); |
110 | } |
111 | EXPORT_SYMBOL_GPL(wmt_ge_copyarea); |
112 | |
113 | int wmt_ge_sync(struct fb_info *p) |
114 | { |
115 | int loops = 5000000; |
116 | while ((readl(addr: regbase + GE_STATUS_OFF) & 4) && --loops) |
117 | cpu_relax(); |
118 | return loops > 0 ? 0 : -EBUSY; |
119 | } |
120 | EXPORT_SYMBOL_GPL(wmt_ge_sync); |
121 | |
122 | static int wmt_ge_rops_probe(struct platform_device *pdev) |
123 | { |
124 | struct resource *res; |
125 | |
126 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
127 | if (res == NULL) { |
128 | dev_err(&pdev->dev, "no I/O memory resource defined\n" ); |
129 | return -ENODEV; |
130 | } |
131 | |
132 | /* Only one ROP engine is presently supported. */ |
133 | if (unlikely(regbase)) { |
134 | WARN_ON(1); |
135 | return -EBUSY; |
136 | } |
137 | |
138 | regbase = ioremap(offset: res->start, size: resource_size(res)); |
139 | if (regbase == NULL) { |
140 | dev_err(&pdev->dev, "failed to map I/O memory\n" ); |
141 | return -EBUSY; |
142 | } |
143 | |
144 | writel(val: 1, addr: regbase + GE_ENABLE_OFF); |
145 | printk(KERN_INFO "Enabled support for WMT GE raster acceleration\n" ); |
146 | |
147 | return 0; |
148 | } |
149 | |
150 | static void wmt_ge_rops_remove(struct platform_device *pdev) |
151 | { |
152 | iounmap(addr: regbase); |
153 | } |
154 | |
155 | static const struct of_device_id wmt_dt_ids[] = { |
156 | { .compatible = "wm,prizm-ge-rops" , }, |
157 | { /* sentinel */ } |
158 | }; |
159 | |
160 | static struct platform_driver wmt_ge_rops_driver = { |
161 | .probe = wmt_ge_rops_probe, |
162 | .remove_new = wmt_ge_rops_remove, |
163 | .driver = { |
164 | .name = "wmt_ge_rops" , |
165 | .of_match_table = wmt_dt_ids, |
166 | }, |
167 | }; |
168 | |
169 | module_platform_driver(wmt_ge_rops_driver); |
170 | |
171 | MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>" ); |
172 | MODULE_DESCRIPTION("Accelerators for raster operations using " |
173 | "WonderMedia Graphics Engine" ); |
174 | MODULE_DEVICE_TABLE(of, wmt_dt_ids); |
175 | |