1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 /* Copyright 2017-2019 Qiang Yu <yuq825@gmail.com> */ 3 4 #include <linux/interrupt.h> 5 #include <linux/iopoll.h> 6 #include <linux/device.h> 7 #include <linux/slab.h> 8 9 #include <drm/lima_drm.h> 10 11 #include "lima_device.h" 12 #include "lima_gp.h" 13 #include "lima_regs.h" 14 15 #define gp_write(reg, data) writel(data, ip->iomem + reg) 16 #define gp_read(reg) readl(ip->iomem + reg) 17 18 static irqreturn_t lima_gp_irq_handler(int irq, void *data) 19 { 20 struct lima_ip *ip = data; 21 struct lima_device *dev = ip->dev; 22 struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp; 23 u32 state = gp_read(LIMA_GP_INT_STAT); 24 u32 status = gp_read(LIMA_GP_STATUS); 25 bool done = false; 26 27 /* for shared irq case */ 28 if (!state) 29 return IRQ_NONE; 30 31 if (state & LIMA_GP_IRQ_MASK_ERROR) { 32 dev_err(dev->dev, "gp error irq state=%x status=%x\n", 33 state, status); 34 35 /* mask all interrupts before hard reset */ 36 gp_write(LIMA_GP_INT_MASK, 0); 37 38 pipe->error = true; 39 done = true; 40 } else { 41 bool valid = state & (LIMA_GP_IRQ_VS_END_CMD_LST | 42 LIMA_GP_IRQ_PLBU_END_CMD_LST); 43 bool active = status & (LIMA_GP_STATUS_VS_ACTIVE | 44 LIMA_GP_STATUS_PLBU_ACTIVE); 45 done = valid && !active; 46 } 47 48 gp_write(LIMA_GP_INT_CLEAR, state); 49 50 if (done) 51 lima_sched_pipe_task_done(pipe); 52 53 return IRQ_HANDLED; 54 } 55 56 static void lima_gp_soft_reset_async(struct lima_ip *ip) 57 { 58 if (ip->data.async_reset) 59 return; 60 61 gp_write(LIMA_GP_INT_MASK, 0); 62 gp_write(LIMA_GP_INT_CLEAR, LIMA_GP_IRQ_RESET_COMPLETED); 63 gp_write(LIMA_GP_CMD, LIMA_GP_CMD_SOFT_RESET); 64 ip->data.async_reset = true; 65 } 66 67 static int lima_gp_soft_reset_async_wait(struct lima_ip *ip) 68 { 69 struct lima_device *dev = ip->dev; 70 int err; 71 u32 v; 72 73 if (!ip->data.async_reset) 74 return 0; 75 76 err = readl_poll_timeout(ip->iomem + LIMA_GP_INT_RAWSTAT, v, 77 v & LIMA_GP_IRQ_RESET_COMPLETED, 78 0, 100); 79 if (err) { 80 dev_err(dev->dev, "gp soft reset time out\n"); 81 return err; 82 } 83 84 gp_write(LIMA_GP_INT_CLEAR, LIMA_GP_IRQ_MASK_ALL); 85 gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED); 86 87 ip->data.async_reset = false; 88 return 0; 89 } 90 91 static int lima_gp_task_validate(struct lima_sched_pipe *pipe, 92 struct lima_sched_task *task) 93 { 94 struct drm_lima_gp_frame *frame = task->frame; 95 u32 *f = frame->frame; 96 (void)pipe; 97 98 if (f[LIMA_GP_VSCL_START_ADDR >> 2] > 99 f[LIMA_GP_VSCL_END_ADDR >> 2] || 100 f[LIMA_GP_PLBUCL_START_ADDR >> 2] > 101 f[LIMA_GP_PLBUCL_END_ADDR >> 2] || 102 f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] > 103 f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]) 104 return -EINVAL; 105 106 if (f[LIMA_GP_VSCL_START_ADDR >> 2] == 107 f[LIMA_GP_VSCL_END_ADDR >> 2] && 108 f[LIMA_GP_PLBUCL_START_ADDR >> 2] == 109 f[LIMA_GP_PLBUCL_END_ADDR >> 2]) 110 return -EINVAL; 111 112 return 0; 113 } 114 115 static void lima_gp_task_run(struct lima_sched_pipe *pipe, 116 struct lima_sched_task *task) 117 { 118 struct lima_ip *ip = pipe->processor[0]; 119 struct drm_lima_gp_frame *frame = task->frame; 120 u32 *f = frame->frame; 121 u32 cmd = 0; 122 int i; 123 124 if (f[LIMA_GP_VSCL_START_ADDR >> 2] != 125 f[LIMA_GP_VSCL_END_ADDR >> 2]) 126 cmd |= LIMA_GP_CMD_START_VS; 127 if (f[LIMA_GP_PLBUCL_START_ADDR >> 2] != 128 f[LIMA_GP_PLBUCL_END_ADDR >> 2]) 129 cmd |= LIMA_GP_CMD_START_PLBU; 130 131 /* before any hw ops, wait last success task async soft reset */ 132 lima_gp_soft_reset_async_wait(ip); 133 134 for (i = 0; i < LIMA_GP_FRAME_REG_NUM; i++) 135 writel(f[i], ip->iomem + LIMA_GP_VSCL_START_ADDR + i * 4); 136 137 gp_write(LIMA_GP_CMD, LIMA_GP_CMD_UPDATE_PLBU_ALLOC); 138 gp_write(LIMA_GP_CMD, cmd); 139 } 140 141 static int lima_gp_hard_reset_poll(struct lima_ip *ip) 142 { 143 gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0xC01A0000); 144 return gp_read(LIMA_GP_PERF_CNT_0_LIMIT) == 0xC01A0000; 145 } 146 147 static int lima_gp_hard_reset(struct lima_ip *ip) 148 { 149 struct lima_device *dev = ip->dev; 150 int ret; 151 152 gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0xC0FFE000); 153 gp_write(LIMA_GP_INT_MASK, 0); 154 gp_write(LIMA_GP_CMD, LIMA_GP_CMD_RESET); 155 ret = lima_poll_timeout(ip, lima_gp_hard_reset_poll, 10, 100); 156 if (ret) { 157 dev_err(dev->dev, "gp hard reset timeout\n"); 158 return ret; 159 } 160 161 gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0); 162 gp_write(LIMA_GP_INT_CLEAR, LIMA_GP_IRQ_MASK_ALL); 163 gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED); 164 return 0; 165 } 166 167 static void lima_gp_task_fini(struct lima_sched_pipe *pipe) 168 { 169 lima_gp_soft_reset_async(pipe->processor[0]); 170 } 171 172 static void lima_gp_task_error(struct lima_sched_pipe *pipe) 173 { 174 struct lima_ip *ip = pipe->processor[0]; 175 176 dev_err(ip->dev->dev, "gp task error int_state=%x status=%x\n", 177 gp_read(LIMA_GP_INT_STAT), gp_read(LIMA_GP_STATUS)); 178 179 lima_gp_hard_reset(ip); 180 } 181 182 static void lima_gp_task_mmu_error(struct lima_sched_pipe *pipe) 183 { 184 lima_sched_pipe_task_done(pipe); 185 } 186 187 static void lima_gp_print_version(struct lima_ip *ip) 188 { 189 u32 version, major, minor; 190 char *name; 191 192 version = gp_read(LIMA_GP_VERSION); 193 major = (version >> 8) & 0xFF; 194 minor = version & 0xFF; 195 switch (version >> 16) { 196 case 0xA07: 197 name = "mali200"; 198 break; 199 case 0xC07: 200 name = "mali300"; 201 break; 202 case 0xB07: 203 name = "mali400"; 204 break; 205 case 0xD07: 206 name = "mali450"; 207 break; 208 default: 209 name = "unknown"; 210 break; 211 } 212 dev_info(ip->dev->dev, "%s - %s version major %d minor %d\n", 213 lima_ip_name(ip), name, major, minor); 214 } 215 216 static struct kmem_cache *lima_gp_task_slab; 217 static int lima_gp_task_slab_refcnt; 218 219 int lima_gp_init(struct lima_ip *ip) 220 { 221 struct lima_device *dev = ip->dev; 222 int err; 223 224 lima_gp_print_version(ip); 225 226 ip->data.async_reset = false; 227 lima_gp_soft_reset_async(ip); 228 err = lima_gp_soft_reset_async_wait(ip); 229 if (err) 230 return err; 231 232 err = devm_request_irq(dev->dev, ip->irq, lima_gp_irq_handler, 233 IRQF_SHARED, lima_ip_name(ip), ip); 234 if (err) { 235 dev_err(dev->dev, "gp %s fail to request irq\n", 236 lima_ip_name(ip)); 237 return err; 238 } 239 240 dev->gp_version = gp_read(LIMA_GP_VERSION); 241 242 return 0; 243 } 244 245 void lima_gp_fini(struct lima_ip *ip) 246 { 247 248 } 249 250 int lima_gp_pipe_init(struct lima_device *dev) 251 { 252 int frame_size = sizeof(struct drm_lima_gp_frame); 253 struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp; 254 255 if (!lima_gp_task_slab) { 256 lima_gp_task_slab = kmem_cache_create_usercopy( 257 "lima_gp_task", sizeof(struct lima_sched_task) + frame_size, 258 0, SLAB_HWCACHE_ALIGN, sizeof(struct lima_sched_task), 259 frame_size, NULL); 260 if (!lima_gp_task_slab) 261 return -ENOMEM; 262 } 263 lima_gp_task_slab_refcnt++; 264 265 pipe->frame_size = frame_size; 266 pipe->task_slab = lima_gp_task_slab; 267 268 pipe->task_validate = lima_gp_task_validate; 269 pipe->task_run = lima_gp_task_run; 270 pipe->task_fini = lima_gp_task_fini; 271 pipe->task_error = lima_gp_task_error; 272 pipe->task_mmu_error = lima_gp_task_mmu_error; 273 274 return 0; 275 } 276 277 void lima_gp_pipe_fini(struct lima_device *dev) 278 { 279 if (!--lima_gp_task_slab_refcnt) { 280 kmem_cache_destroy(lima_gp_task_slab); 281 lima_gp_task_slab = NULL; 282 } 283 } 284