vsp1_drv.c revision 83453a7cc8b703ce818c24c2298822b0b179e652
1/* 2 * vsp1_drv.c -- R-Car VSP1 Driver 3 * 4 * Copyright (C) 2013 Renesas Corporation 5 * 6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 */ 13 14#include <linux/clk.h> 15#include <linux/delay.h> 16#include <linux/device.h> 17#include <linux/interrupt.h> 18#include <linux/module.h> 19#include <linux/platform_device.h> 20#include <linux/videodev2.h> 21 22#include "vsp1.h" 23#include "vsp1_lif.h" 24#include "vsp1_rwpf.h" 25#include "vsp1_uds.h" 26 27/* ----------------------------------------------------------------------------- 28 * Interrupt Handling 29 */ 30 31static irqreturn_t vsp1_irq_handler(int irq, void *data) 32{ 33 u32 mask = VI6_WFP_IRQ_STA_DFE | VI6_WFP_IRQ_STA_FRE; 34 struct vsp1_device *vsp1 = data; 35 irqreturn_t ret = IRQ_NONE; 36 unsigned int i; 37 38 for (i = 0; i < vsp1->pdata->wpf_count; ++i) { 39 struct vsp1_rwpf *wpf = vsp1->wpf[i]; 40 struct vsp1_pipeline *pipe; 41 u32 status; 42 43 if (wpf == NULL) 44 continue; 45 46 pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); 47 status = vsp1_read(vsp1, VI6_WPF_IRQ_STA(i)); 48 vsp1_write(vsp1, VI6_WPF_IRQ_STA(i), ~status & mask); 49 50 if (status & VI6_WFP_IRQ_STA_FRE) { 51 vsp1_pipeline_frame_end(pipe); 52 ret = IRQ_HANDLED; 53 } 54 } 55 56 return ret; 57} 58 59/* ----------------------------------------------------------------------------- 60 * Entities 61 */ 62 63/* 64 * vsp1_create_links - Create links from all sources to the given sink 65 * 66 * This function creates media links from all valid sources to the given sink 67 * pad. Links that would be invalid according to the VSP1 hardware capabilities 68 * are skipped. Those include all links 69 * 70 * - from a UDS to a UDS (UDS entities can't be chained) 71 * - from an entity to itself (no loops are allowed) 72 */ 73static int vsp1_create_links(struct vsp1_device *vsp1, struct vsp1_entity *sink) 74{ 75 struct media_entity *entity = &sink->subdev.entity; 76 struct vsp1_entity *source; 77 unsigned int pad; 78 int ret; 79 80 list_for_each_entry(source, &vsp1->entities, list_dev) { 81 u32 flags; 82 83 if (source->type == sink->type) 84 continue; 85 86 if (source->type == VSP1_ENTITY_LIF || 87 source->type == VSP1_ENTITY_WPF) 88 continue; 89 90 flags = source->type == VSP1_ENTITY_RPF && 91 sink->type == VSP1_ENTITY_WPF && 92 source->index == sink->index 93 ? MEDIA_LNK_FL_ENABLED : 0; 94 95 for (pad = 0; pad < entity->num_pads; ++pad) { 96 if (!(entity->pads[pad].flags & MEDIA_PAD_FL_SINK)) 97 continue; 98 99 ret = media_entity_create_link(&source->subdev.entity, 100 source->source_pad, 101 entity, pad, flags); 102 if (ret < 0) 103 return ret; 104 105 if (flags & MEDIA_LNK_FL_ENABLED) 106 source->sink = entity; 107 } 108 } 109 110 return 0; 111} 112 113static void vsp1_destroy_entities(struct vsp1_device *vsp1) 114{ 115 struct vsp1_entity *entity; 116 struct vsp1_entity *next; 117 118 list_for_each_entry_safe(entity, next, &vsp1->entities, list_dev) { 119 list_del(&entity->list_dev); 120 vsp1_entity_destroy(entity); 121 } 122 123 v4l2_device_unregister(&vsp1->v4l2_dev); 124 media_device_unregister(&vsp1->media_dev); 125} 126 127static int vsp1_create_entities(struct vsp1_device *vsp1) 128{ 129 struct media_device *mdev = &vsp1->media_dev; 130 struct v4l2_device *vdev = &vsp1->v4l2_dev; 131 struct vsp1_entity *entity; 132 unsigned int i; 133 int ret; 134 135 mdev->dev = vsp1->dev; 136 strlcpy(mdev->model, "VSP1", sizeof(mdev->model)); 137 ret = media_device_register(mdev); 138 if (ret < 0) { 139 dev_err(vsp1->dev, "media device registration failed (%d)\n", 140 ret); 141 return ret; 142 } 143 144 vdev->mdev = mdev; 145 ret = v4l2_device_register(vsp1->dev, vdev); 146 if (ret < 0) { 147 dev_err(vsp1->dev, "V4L2 device registration failed (%d)\n", 148 ret); 149 goto done; 150 } 151 152 /* Instantiate all the entities. */ 153 if (vsp1->pdata->features & VSP1_HAS_LIF) { 154 vsp1->lif = vsp1_lif_create(vsp1); 155 if (IS_ERR(vsp1->lif)) { 156 ret = PTR_ERR(vsp1->lif); 157 goto done; 158 } 159 160 list_add_tail(&vsp1->lif->entity.list_dev, &vsp1->entities); 161 } 162 163 for (i = 0; i < vsp1->pdata->rpf_count; ++i) { 164 struct vsp1_rwpf *rpf; 165 166 rpf = vsp1_rpf_create(vsp1, i); 167 if (IS_ERR(rpf)) { 168 ret = PTR_ERR(rpf); 169 goto done; 170 } 171 172 vsp1->rpf[i] = rpf; 173 list_add_tail(&rpf->entity.list_dev, &vsp1->entities); 174 } 175 176 for (i = 0; i < vsp1->pdata->uds_count; ++i) { 177 struct vsp1_uds *uds; 178 179 uds = vsp1_uds_create(vsp1, i); 180 if (IS_ERR(uds)) { 181 ret = PTR_ERR(uds); 182 goto done; 183 } 184 185 vsp1->uds[i] = uds; 186 list_add_tail(&uds->entity.list_dev, &vsp1->entities); 187 } 188 189 for (i = 0; i < vsp1->pdata->wpf_count; ++i) { 190 struct vsp1_rwpf *wpf; 191 192 wpf = vsp1_wpf_create(vsp1, i); 193 if (IS_ERR(wpf)) { 194 ret = PTR_ERR(wpf); 195 goto done; 196 } 197 198 vsp1->wpf[i] = wpf; 199 list_add_tail(&wpf->entity.list_dev, &vsp1->entities); 200 } 201 202 /* Create links. */ 203 list_for_each_entry(entity, &vsp1->entities, list_dev) { 204 if (entity->type == VSP1_ENTITY_LIF || 205 entity->type == VSP1_ENTITY_RPF) 206 continue; 207 208 ret = vsp1_create_links(vsp1, entity); 209 if (ret < 0) 210 goto done; 211 } 212 213 if (vsp1->pdata->features & VSP1_HAS_LIF) { 214 ret = media_entity_create_link( 215 &vsp1->wpf[0]->entity.subdev.entity, RWPF_PAD_SOURCE, 216 &vsp1->lif->entity.subdev.entity, LIF_PAD_SINK, 0); 217 if (ret < 0) 218 return ret; 219 } 220 221 /* Register all subdevs. */ 222 list_for_each_entry(entity, &vsp1->entities, list_dev) { 223 ret = v4l2_device_register_subdev(&vsp1->v4l2_dev, 224 &entity->subdev); 225 if (ret < 0) 226 goto done; 227 } 228 229 ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev); 230 231done: 232 if (ret < 0) 233 vsp1_destroy_entities(vsp1); 234 235 return ret; 236} 237 238static int vsp1_device_init(struct vsp1_device *vsp1) 239{ 240 unsigned int i; 241 u32 status; 242 243 /* Reset any channel that might be running. */ 244 status = vsp1_read(vsp1, VI6_STATUS); 245 246 for (i = 0; i < vsp1->pdata->wpf_count; ++i) { 247 unsigned int timeout; 248 249 if (!(status & VI6_STATUS_SYS_ACT(i))) 250 continue; 251 252 vsp1_write(vsp1, VI6_SRESET, VI6_SRESET_SRTS(i)); 253 for (timeout = 10; timeout > 0; --timeout) { 254 status = vsp1_read(vsp1, VI6_STATUS); 255 if (!(status & VI6_STATUS_SYS_ACT(i))) 256 break; 257 258 usleep_range(1000, 2000); 259 } 260 261 if (!timeout) { 262 dev_err(vsp1->dev, "failed to reset wpf.%u\n", i); 263 return -ETIMEDOUT; 264 } 265 } 266 267 vsp1_write(vsp1, VI6_CLK_DCSWT, (8 << VI6_CLK_DCSWT_CSTPW_SHIFT) | 268 (8 << VI6_CLK_DCSWT_CSTRW_SHIFT)); 269 270 for (i = 0; i < vsp1->pdata->rpf_count; ++i) 271 vsp1_write(vsp1, VI6_DPR_RPF_ROUTE(i), VI6_DPR_NODE_UNUSED); 272 273 for (i = 0; i < vsp1->pdata->uds_count; ++i) 274 vsp1_write(vsp1, VI6_DPR_UDS_ROUTE(i), VI6_DPR_NODE_UNUSED); 275 276 vsp1_write(vsp1, VI6_DPR_SRU_ROUTE, VI6_DPR_NODE_UNUSED); 277 vsp1_write(vsp1, VI6_DPR_LUT_ROUTE, VI6_DPR_NODE_UNUSED); 278 vsp1_write(vsp1, VI6_DPR_CLU_ROUTE, VI6_DPR_NODE_UNUSED); 279 vsp1_write(vsp1, VI6_DPR_HST_ROUTE, VI6_DPR_NODE_UNUSED); 280 vsp1_write(vsp1, VI6_DPR_HSI_ROUTE, VI6_DPR_NODE_UNUSED); 281 vsp1_write(vsp1, VI6_DPR_BRU_ROUTE, VI6_DPR_NODE_UNUSED); 282 283 vsp1_write(vsp1, VI6_DPR_HGO_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) | 284 (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT)); 285 vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) | 286 (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT)); 287 288 return 0; 289} 290 291/* 292 * vsp1_device_get - Acquire the VSP1 device 293 * 294 * Increment the VSP1 reference count and initialize the device if the first 295 * reference is taken. 296 * 297 * Return a pointer to the VSP1 device or NULL if an error occured. 298 */ 299struct vsp1_device *vsp1_device_get(struct vsp1_device *vsp1) 300{ 301 struct vsp1_device *__vsp1 = vsp1; 302 int ret; 303 304 mutex_lock(&vsp1->lock); 305 if (vsp1->ref_count > 0) 306 goto done; 307 308 ret = clk_prepare_enable(vsp1->clock); 309 if (ret < 0) { 310 __vsp1 = NULL; 311 goto done; 312 } 313 314 ret = vsp1_device_init(vsp1); 315 if (ret < 0) { 316 clk_disable_unprepare(vsp1->clock); 317 __vsp1 = NULL; 318 goto done; 319 } 320 321done: 322 if (__vsp1) 323 vsp1->ref_count++; 324 325 mutex_unlock(&vsp1->lock); 326 return __vsp1; 327} 328 329/* 330 * vsp1_device_put - Release the VSP1 device 331 * 332 * Decrement the VSP1 reference count and cleanup the device if the last 333 * reference is released. 334 */ 335void vsp1_device_put(struct vsp1_device *vsp1) 336{ 337 mutex_lock(&vsp1->lock); 338 339 if (--vsp1->ref_count == 0) 340 clk_disable_unprepare(vsp1->clock); 341 342 mutex_unlock(&vsp1->lock); 343} 344 345/* ----------------------------------------------------------------------------- 346 * Power Management 347 */ 348 349#ifdef CONFIG_PM_SLEEP 350static int vsp1_pm_suspend(struct device *dev) 351{ 352 struct vsp1_device *vsp1 = dev_get_drvdata(dev); 353 354 WARN_ON(mutex_is_locked(&vsp1->lock)); 355 356 if (vsp1->ref_count == 0) 357 return 0; 358 359 clk_disable_unprepare(vsp1->clock); 360 return 0; 361} 362 363static int vsp1_pm_resume(struct device *dev) 364{ 365 struct vsp1_device *vsp1 = dev_get_drvdata(dev); 366 367 WARN_ON(mutex_is_locked(&vsp1->lock)); 368 369 if (vsp1->ref_count) 370 return 0; 371 372 return clk_prepare_enable(vsp1->clock); 373} 374#endif 375 376static const struct dev_pm_ops vsp1_pm_ops = { 377 SET_SYSTEM_SLEEP_PM_OPS(vsp1_pm_suspend, vsp1_pm_resume) 378}; 379 380/* ----------------------------------------------------------------------------- 381 * Platform Driver 382 */ 383 384static struct vsp1_platform_data * 385vsp1_get_platform_data(struct platform_device *pdev) 386{ 387 struct vsp1_platform_data *pdata = pdev->dev.platform_data; 388 389 if (pdata == NULL) { 390 dev_err(&pdev->dev, "missing platform data\n"); 391 return NULL; 392 } 393 394 if (pdata->rpf_count <= 0 || pdata->rpf_count > VPS1_MAX_RPF) { 395 dev_err(&pdev->dev, "invalid number of RPF (%u)\n", 396 pdata->rpf_count); 397 return NULL; 398 } 399 400 if (pdata->uds_count <= 0 || pdata->uds_count > VPS1_MAX_UDS) { 401 dev_err(&pdev->dev, "invalid number of UDS (%u)\n", 402 pdata->uds_count); 403 return NULL; 404 } 405 406 if (pdata->wpf_count <= 0 || pdata->wpf_count > VPS1_MAX_WPF) { 407 dev_err(&pdev->dev, "invalid number of WPF (%u)\n", 408 pdata->wpf_count); 409 return NULL; 410 } 411 412 return pdata; 413} 414 415static int vsp1_probe(struct platform_device *pdev) 416{ 417 struct vsp1_device *vsp1; 418 struct resource *irq; 419 struct resource *io; 420 int ret; 421 422 vsp1 = devm_kzalloc(&pdev->dev, sizeof(*vsp1), GFP_KERNEL); 423 if (vsp1 == NULL) 424 return -ENOMEM; 425 426 vsp1->dev = &pdev->dev; 427 mutex_init(&vsp1->lock); 428 INIT_LIST_HEAD(&vsp1->entities); 429 430 vsp1->pdata = vsp1_get_platform_data(pdev); 431 if (vsp1->pdata == NULL) 432 return -ENODEV; 433 434 /* I/O, IRQ and clock resources */ 435 io = platform_get_resource(pdev, IORESOURCE_MEM, 0); 436 vsp1->mmio = devm_ioremap_resource(&pdev->dev, io); 437 if (IS_ERR((void *)vsp1->mmio)) 438 return PTR_ERR((void *)vsp1->mmio); 439 440 vsp1->clock = devm_clk_get(&pdev->dev, NULL); 441 if (IS_ERR(vsp1->clock)) { 442 dev_err(&pdev->dev, "failed to get clock\n"); 443 return PTR_ERR(vsp1->clock); 444 } 445 446 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 447 if (!irq) { 448 dev_err(&pdev->dev, "missing IRQ\n"); 449 return -EINVAL; 450 } 451 452 ret = devm_request_irq(&pdev->dev, irq->start, vsp1_irq_handler, 453 IRQF_SHARED, dev_name(&pdev->dev), vsp1); 454 if (ret < 0) { 455 dev_err(&pdev->dev, "failed to request IRQ\n"); 456 return ret; 457 } 458 459 /* Instanciate entities */ 460 ret = vsp1_create_entities(vsp1); 461 if (ret < 0) { 462 dev_err(&pdev->dev, "failed to create entities\n"); 463 return ret; 464 } 465 466 platform_set_drvdata(pdev, vsp1); 467 468 return 0; 469} 470 471static int vsp1_remove(struct platform_device *pdev) 472{ 473 struct vsp1_device *vsp1 = platform_get_drvdata(pdev); 474 475 vsp1_destroy_entities(vsp1); 476 477 return 0; 478} 479 480static struct platform_driver vsp1_platform_driver = { 481 .probe = vsp1_probe, 482 .remove = vsp1_remove, 483 .driver = { 484 .owner = THIS_MODULE, 485 .name = "vsp1", 486 .pm = &vsp1_pm_ops, 487 }, 488}; 489 490module_platform_driver(vsp1_platform_driver); 491 492MODULE_ALIAS("vsp1"); 493MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); 494MODULE_DESCRIPTION("Renesas VSP1 Driver"); 495MODULE_LICENSE("GPL"); 496