1 /*
2 * Copyright (c) 2018 Loongson Technology Co., Ltd.
3 * Authors:
4 * Chen Zhu <zhuchen@loongson.cn>
5 * Yaling Fang <fangyaling@loongson.cn>
6 * Dandan Zhang <zhangdandan@loongson.cn>
7 * Huacai Chen <chenhc@lemote.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13
14 #include <asm/cacheflush.h>
15 #include <drm/drm_gem_cma_helper.h>
16 #include "loongson_drv.h"
17
flush_scache_range(void *addr, unsigned long size)18 static void flush_scache_range(void *addr, unsigned long size)
19 {
20 int inc;
21 unsigned long start, end;
22
23 start = (unsigned long)addr;
24 end = (unsigned long)addr + size;
25 inc = cpu_last_level_cache_line_size();
26
27 for (; start < end; start += inc)
28 flush_cache_line(Cache_LEAF3, start);
29 }
30
31 /*
32 Hide the cursor off screen. We can't disable the cursor hardware because it
33 takes too long to re-activate and causes momentary corruption
34 */
loongson_hide_cursor(struct drm_crtc *crtc)35 static void loongson_hide_cursor(struct drm_crtc *crtc)
36 {
37 unsigned long flags;
38 volatile void __iomem *base;
39 struct drm_device *dev = crtc->dev;
40 struct loongson_drm_device *ldev = (struct loongson_drm_device *)dev->dev_private;
41 struct loongson_crtc *loongson_crtc = to_loongson_crtc(crtc);
42 unsigned int tmp, crtc_id = loongson_crtc->crtc_id;
43
44 base = ldev->mmio;
45 tmp = readl(base + FB_CUR_CFG_REG);
46 tmp &= ~0xff;
47 if (clone_mode(ldev)) {
48 spin_lock_irqsave(&loongson_reglock, flags);
49 writel(tmp | 0x00, base + FB_CUR_CFG_REG);
50 spin_unlock_irqrestore(&loongson_reglock, flags);
51 ldev->cursor_showed = false;
52 } else {
53 if (ldev->cursor_crtc_id != crtc_id)
54 return;
55
56 spin_lock_irqsave(&loongson_reglock, flags);
57 if (crtc_id) {
58 writel(tmp | 0x10, base + FB_CUR_CFG_REG);
59 } else {
60 writel(tmp | 0x00, base + FB_CUR_CFG_REG);
61 }
62 spin_unlock_irqrestore(&loongson_reglock, flags);
63 ldev->cursor_showed = false;
64 }
65 }
66
loongson_show_cursor(struct drm_crtc *crtc)67 static void loongson_show_cursor(struct drm_crtc *crtc)
68 {
69 unsigned long flags;
70 volatile void __iomem *base;
71 struct drm_device *dev = crtc->dev;
72 struct loongson_drm_device *ldev = (struct loongson_drm_device *)dev->dev_private;
73 struct loongson_crtc *loongson_crtc = to_loongson_crtc(crtc);
74 unsigned int crtc_id = loongson_crtc->crtc_id;
75
76 base = ldev->mmio;
77 if (clone_mode(ldev)) {
78 spin_lock_irqsave(&loongson_reglock, flags);
79 writel(0x00050202, base + FB_CUR_CFG_REG);
80 spin_unlock_irqrestore(&loongson_reglock, flags);
81 ldev->cursor_crtc_id = 0;
82 ldev->cursor_showed = true;
83 } else {
84 if (ldev->cursor_crtc_id == crtc_id) {
85 spin_lock_irqsave(&loongson_reglock, flags);
86 if(crtc_id == 0){
87 writel(0x00050202, base + FB_CUR_CFG_REG);
88 }else{
89 writel(0x00050212, base + FB_CUR_CFG_REG);
90 }
91 spin_unlock_irqrestore(&loongson_reglock, flags);
92
93 ldev->cursor_showed = true;
94 ldev->cursor_crtc_id = crtc_id;
95 }
96 }
97 }
98
loongson_crtc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height, int32_t hot_x, int32_t hot_y)99 int loongson_crtc_cursor_set2(struct drm_crtc *crtc,
100 struct drm_file *file_priv,
101 uint32_t handle,
102 uint32_t width,
103 uint32_t height,
104 int32_t hot_x, int32_t hot_y)
105 {
106 u32 gpu_addr;
107 unsigned long flags;
108 unsigned int crtc_id;
109 volatile void __iomem *base;
110 struct drm_gem_object *obj;
111 struct drm_device *dev = crtc->dev;
112 struct loongson_crtc *loongson_crtc = to_loongson_crtc(crtc);
113 struct loongson_drm_device *ldev = (struct loongson_drm_device *)dev->dev_private;
114 struct drm_gem_cma_object *cma, *cursor = ldev->cursor;
115
116 base = ldev->mmio;
117 crtc_id = loongson_crtc->crtc_id;
118
119 if ((width != 32 || height != 32) && handle) {
120 return -EINVAL;
121 }
122
123 if (!handle || !file_priv) {
124 loongson_hide_cursor(crtc);
125 return 0;
126 }
127
128 obj = drm_gem_object_lookup(file_priv, handle);
129 if (!obj)
130 return -ENOENT;
131
132 cma = to_drm_gem_cma_obj(obj);
133
134 flush_scache_range(cma->vaddr, 32*32*4);
135 memcpy(cursor->vaddr, cma->vaddr, 32*32*4);
136
137 /* Program gpu address of cursor buffer */
138 gpu_addr = ldev->cursor->paddr;
139 spin_lock_irqsave(&loongson_reglock, flags);
140 writel(gpu_addr, base + FB_CUR_ADDR_REG);
141 writel(0x00eeeeee, base + FB_CUR_BACK_REG);
142 writel(0x00aaaaaa, base + FB_CUR_FORE_REG);
143 spin_unlock_irqrestore(&loongson_reglock, flags);
144
145 loongson_show_cursor(crtc);
146
147 drm_gem_object_put(obj);
148
149 return 0;
150 }
151
loongson_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)152 int loongson_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
153 {
154 unsigned long flags;
155 unsigned int tmp, crtc_id;
156 int xorign = 0, yorign = 0;
157 volatile void __iomem *base;
158 struct loongson_crtc *loongson_crtc = to_loongson_crtc(crtc);
159 struct loongson_drm_device *ldev = (struct loongson_drm_device *)crtc->dev->dev_private;
160
161 base = ldev->mmio;
162 crtc_id = loongson_crtc->crtc_id;
163
164 /* upper edge condition */
165 yorign = y + crtc->y;
166 if (yorign < 0)
167 y = 0;
168
169 /* left edge conditon */
170 xorign = x + crtc->x;
171 if (xorign < 0)
172 x = 0;
173
174 /* move from one crtc to another, check which crtc should he shown
175 * the x or y < 0, it means the cursor it out of current review,
176 * && xorign/ yorign > 0, it means the cursor is in the framebuffer
177 * but not in curren review */
178 if ((x < 0 && xorign > 0) || (y < 0 && yorign > 0)) {
179 if(ldev->cursor_crtc_id == crtc_id && !clone_mode(ldev))
180 /*the cursor is not show, so hide if the (x,y) is in active crtc*/
181 loongson_hide_cursor(crtc);
182 return 0;
183 }
184
185 if (x < 0)
186 x = 0;
187 if (y < 0)
188 y = 0;
189
190 tmp = x & 0xffff;
191 tmp |= y << 16;
192 spin_lock_irqsave(&loongson_reglock, flags);
193 writel(tmp, base + FB_CUR_LOC_ADDR_REG);
194 spin_unlock_irqrestore(&loongson_reglock, flags);
195 if (ldev->cursor_crtc_id != crtc_id && !clone_mode(ldev)) {
196 ldev->cursor_crtc_id = crtc_id;
197 ldev->cursor_showed = false;
198 }
199 if (!ldev->cursor_showed)
200 loongson_show_cursor(crtc);
201
202 return 0;
203 }
204