Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpu: host1x: Add syncpoint base support

This patch adds support for hardware syncpoint bases. This creates
a simple mechanism to stall the command FIFO until an operation is
completed.

Signed-off-by: Arto Merilainen <amerilainen@nvidia.com>
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>

authored by

Arto Merilainen and committed by
Thierry Reding
f5a954fe 8736fe81

+92 -2
+2
drivers/gpu/host1x/dev.h
··· 27 27 #include "job.h" 28 28 29 29 struct host1x_syncpt; 30 + struct host1x_syncpt_base; 30 31 struct host1x_channel; 31 32 struct host1x_cdma; 32 33 struct host1x_job; ··· 103 102 104 103 void __iomem *regs; 105 104 struct host1x_syncpt *syncpt; 105 + struct host1x_syncpt_base *bases; 106 106 struct device *dev; 107 107 struct clk *clk; 108 108
+20
drivers/gpu/host1x/hw/channel_hw.c
··· 67 67 } 68 68 } 69 69 70 + static inline void synchronize_syncpt_base(struct host1x_job *job) 71 + { 72 + struct host1x *host = dev_get_drvdata(job->channel->dev->parent); 73 + struct host1x_syncpt *sp = host->syncpt + job->syncpt_id; 74 + u32 id, value; 75 + 76 + value = host1x_syncpt_read_max(sp); 77 + id = sp->base->id; 78 + 79 + host1x_cdma_push(&job->channel->cdma, 80 + host1x_opcode_setclass(HOST1X_CLASS_HOST1X, 81 + HOST1X_UCLASS_LOAD_SYNCPT_BASE, 1), 82 + HOST1X_UCLASS_LOAD_SYNCPT_BASE_BASE_INDX_F(id) | 83 + HOST1X_UCLASS_LOAD_SYNCPT_BASE_VALUE_F(value)); 84 + } 85 + 70 86 static int channel_submit(struct host1x_job *job) 71 87 { 72 88 struct host1x_channel *ch = job->channel; ··· 133 117 host1x_class_host_wait_syncpt(job->syncpt_id, 134 118 host1x_syncpt_read_max(sp))); 135 119 } 120 + 121 + /* Synchronize base register to allow using it for relative waiting */ 122 + if (sp->base) 123 + synchronize_syncpt_base(job); 136 124 137 125 syncval = host1x_syncpt_incr_max(sp, user_syncpt_incrs); 138 126
+6
drivers/gpu/host1x/hw/hw_host1x01_uclass.h
··· 111 111 } 112 112 #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \ 113 113 host1x_uclass_wait_syncpt_base_offset_f(v) 114 + static inline u32 host1x_uclass_load_syncpt_base_r(void) 115 + { 116 + return 0xb; 117 + } 118 + #define HOST1X_UCLASS_LOAD_SYNCPT_BASE \ 119 + host1x_uclass_load_syncpt_base_r() 114 120 static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v) 115 121 { 116 122 return (v & 0xff) << 24;
+53 -2
drivers/gpu/host1x/syncpt.c
··· 30 30 #define SYNCPT_CHECK_PERIOD (2 * HZ) 31 31 #define MAX_STUCK_CHECK_COUNT 15 32 32 33 + static struct host1x_syncpt_base * 34 + host1x_syncpt_base_request(struct host1x *host) 35 + { 36 + struct host1x_syncpt_base *bases = host->bases; 37 + unsigned int i; 38 + 39 + for (i = 0; i < host->info->nb_bases; i++) 40 + if (!bases[i].requested) 41 + break; 42 + 43 + if (i >= host->info->nb_bases) 44 + return NULL; 45 + 46 + bases[i].requested = true; 47 + return &bases[i]; 48 + } 49 + 50 + static void host1x_syncpt_base_free(struct host1x_syncpt_base *base) 51 + { 52 + if (base) 53 + base->requested = false; 54 + } 55 + 33 56 static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host, 34 57 struct device *dev, 35 58 unsigned long flags) ··· 66 43 67 44 if (i >= host->info->nb_pts) 68 45 return NULL; 46 + 47 + if (flags & HOST1X_SYNCPT_HAS_BASE) { 48 + sp->base = host1x_syncpt_base_request(host); 49 + if (!sp->base) 50 + return NULL; 51 + } 69 52 70 53 name = kasprintf(GFP_KERNEL, "%02d-%s", sp->id, 71 54 dev ? dev_name(dev) : NULL); ··· 336 307 337 308 int host1x_syncpt_init(struct host1x *host) 338 309 { 310 + struct host1x_syncpt_base *bases; 339 311 struct host1x_syncpt *syncpt; 340 312 int i; 341 313 342 314 syncpt = devm_kzalloc(host->dev, sizeof(*syncpt) * host->info->nb_pts, 343 - GFP_KERNEL); 315 + GFP_KERNEL); 344 316 if (!syncpt) 345 317 return -ENOMEM; 346 318 347 - for (i = 0; i < host->info->nb_pts; ++i) { 319 + bases = devm_kzalloc(host->dev, sizeof(*bases) * host->info->nb_bases, 320 + GFP_KERNEL); 321 + if (!bases) 322 + return -ENOMEM; 323 + 324 + for (i = 0; i < host->info->nb_pts; i++) { 348 325 syncpt[i].id = i; 349 326 syncpt[i].host = host; 350 327 } 351 328 329 + for (i = 0; i < host->info->nb_bases; i++) 330 + bases[i].id = i; 331 + 352 332 host->syncpt = syncpt; 333 + host->bases = bases; 353 334 354 335 host1x_syncpt_restore(host); 355 336 ··· 383 344 if (!sp) 384 345 return; 385 346 347 + host1x_syncpt_base_free(sp->base); 386 348 kfree(sp->name); 349 + sp->base = NULL; 387 350 sp->dev = NULL; 388 351 sp->name = NULL; 389 352 sp->client_managed = false; ··· 438 397 if (host->info->nb_pts < id) 439 398 return NULL; 440 399 return host->syncpt + id; 400 + } 401 + 402 + struct host1x_syncpt_base *host1x_syncpt_get_base(struct host1x_syncpt *sp) 403 + { 404 + return sp ? sp->base : NULL; 405 + } 406 + 407 + u32 host1x_syncpt_base_id(struct host1x_syncpt_base *base) 408 + { 409 + return base->id; 441 410 }
+6
drivers/gpu/host1x/syncpt.h
··· 31 31 /* Reserved for replacing an expired wait with a NOP */ 32 32 #define HOST1X_SYNCPT_RESERVED 0 33 33 34 + struct host1x_syncpt_base { 35 + unsigned int id; 36 + bool requested; 37 + }; 38 + 34 39 struct host1x_syncpt { 35 40 int id; 36 41 atomic_t min_val; ··· 45 40 bool client_managed; 46 41 struct host1x *host; 47 42 struct device *dev; 43 + struct host1x_syncpt_base *base; 48 44 49 45 /* interrupt data */ 50 46 struct host1x_syncpt_intr intr;
+5
include/linux/host1x.h
··· 125 125 */ 126 126 127 127 #define HOST1X_SYNCPT_CLIENT_MANAGED (1 << 0) 128 + #define HOST1X_SYNCPT_HAS_BASE (1 << 1) 128 129 130 + struct host1x_syncpt_base; 129 131 struct host1x_syncpt; 130 132 struct host1x; 131 133 ··· 141 139 struct host1x_syncpt *host1x_syncpt_request(struct device *dev, 142 140 unsigned long flags); 143 141 void host1x_syncpt_free(struct host1x_syncpt *sp); 142 + 143 + struct host1x_syncpt_base *host1x_syncpt_get_base(struct host1x_syncpt *sp); 144 + u32 host1x_syncpt_base_id(struct host1x_syncpt_base *base); 144 145 145 146 /* 146 147 * host1x channel