root/drivers/gpu/drm/lima/lima_gp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lima_gp_irq_handler
  2. lima_gp_soft_reset_async
  3. lima_gp_soft_reset_async_wait
  4. lima_gp_task_validate
  5. lima_gp_task_run
  6. lima_gp_hard_reset_poll
  7. lima_gp_hard_reset
  8. lima_gp_task_fini
  9. lima_gp_task_error
  10. lima_gp_task_mmu_error
  11. lima_gp_print_version
  12. lima_gp_init
  13. lima_gp_fini
  14. lima_gp_pipe_init
  15. lima_gp_pipe_fini

   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 }

/* [<][>][^][v][top][bottom][index][help] */