1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2021-2022 Bootlin 4 * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com> 5 */ 6 7#include <linux/clk.h> 8#include <linux/dma-mapping.h> 9#include <linux/err.h> 10#include <linux/interrupt.h> 11#include <linux/module.h> 12#include <linux/of.h> 13#include <linux/platform_device.h> 14#include <linux/pm_runtime.h> 15#include <linux/regmap.h> 16#include <linux/reset.h> 17#include <media/v4l2-device.h> 18#include <media/v4l2-mc.h> 19 20#include "sun6i_isp.h" 21#include "sun6i_isp_capture.h" 22#include "sun6i_isp_params.h" 23#include "sun6i_isp_proc.h" 24#include "sun6i_isp_reg.h" 25 26/* Helpers */ 27 28u32 sun6i_isp_load_read(struct sun6i_isp_device *isp_dev, u32 offset) 29{ 30 u32 *data = (u32 *)(isp_dev->tables.load.data + offset); 31 32 return *data; 33} 34 35void sun6i_isp_load_write(struct sun6i_isp_device *isp_dev, u32 offset, 36 u32 value) 37{ 38 u32 *data = (u32 *)(isp_dev->tables.load.data + offset); 39 40 *data = value; 41} 42 43/* State */ 44 45/* 46 * The ISP works with a load buffer, which gets copied to the actual registers 47 * by the hardware before processing a frame when a specific flag is set. 48 * This is represented by tracking the ISP state in the different parts of 49 * the code with explicit sync points: 50 * - state update: to update the load buffer for the next frame if necessary; 51 * - state complete: to indicate that the state update was applied. 52 */ 53 54static void sun6i_isp_state_ready(struct sun6i_isp_device *isp_dev) 55{ 56 struct regmap *regmap = isp_dev->regmap; 57 u32 value; 58 59 regmap_read(regmap, SUN6I_ISP_FE_CTRL_REG, &value); 60 value |= SUN6I_ISP_FE_CTRL_PARA_READY; 61 regmap_write(regmap, SUN6I_ISP_FE_CTRL_REG, value); 62} 63 64static void sun6i_isp_state_complete(struct sun6i_isp_device *isp_dev) 65{ 66 unsigned long flags; 67 68 spin_lock_irqsave(&isp_dev->state_lock, flags); 69 70 sun6i_isp_capture_state_complete(isp_dev); 71 sun6i_isp_params_state_complete(isp_dev); 72 73 spin_unlock_irqrestore(&isp_dev->state_lock, flags); 74} 75 76void sun6i_isp_state_update(struct sun6i_isp_device *isp_dev, bool ready_hold) 77{ 78 bool update = false; 79 unsigned long flags; 80 81 spin_lock_irqsave(&isp_dev->state_lock, flags); 82 83 sun6i_isp_capture_state_update(isp_dev, &update); 84 sun6i_isp_params_state_update(isp_dev, &update); 85 86 if (update && !ready_hold) 87 sun6i_isp_state_ready(isp_dev); 88 89 spin_unlock_irqrestore(&isp_dev->state_lock, flags); 90} 91 92/* Tables */ 93 94static int sun6i_isp_table_setup(struct sun6i_isp_device *isp_dev, 95 struct sun6i_isp_table *table) 96{ 97 table->data = dma_alloc_coherent(isp_dev->dev, table->size, 98 &table->address, GFP_KERNEL); 99 if (!table->data) 100 return -ENOMEM; 101 102 return 0; 103} 104 105static void sun6i_isp_table_cleanup(struct sun6i_isp_device *isp_dev, 106 struct sun6i_isp_table *table) 107{ 108 dma_free_coherent(isp_dev->dev, table->size, table->data, 109 table->address); 110} 111 112void sun6i_isp_tables_configure(struct sun6i_isp_device *isp_dev) 113{ 114 struct regmap *regmap = isp_dev->regmap; 115 116 regmap_write(regmap, SUN6I_ISP_REG_LOAD_ADDR_REG, 117 SUN6I_ISP_ADDR_VALUE(isp_dev->tables.load.address)); 118 119 regmap_write(regmap, SUN6I_ISP_REG_SAVE_ADDR_REG, 120 SUN6I_ISP_ADDR_VALUE(isp_dev->tables.save.address)); 121 122 regmap_write(regmap, SUN6I_ISP_LUT_TABLE_ADDR_REG, 123 SUN6I_ISP_ADDR_VALUE(isp_dev->tables.lut.address)); 124 125 regmap_write(regmap, SUN6I_ISP_DRC_TABLE_ADDR_REG, 126 SUN6I_ISP_ADDR_VALUE(isp_dev->tables.drc.address)); 127 128 regmap_write(regmap, SUN6I_ISP_STATS_ADDR_REG, 129 SUN6I_ISP_ADDR_VALUE(isp_dev->tables.stats.address)); 130} 131 132static int sun6i_isp_tables_setup(struct sun6i_isp_device *isp_dev, 133 const struct sun6i_isp_variant *variant) 134{ 135 struct sun6i_isp_tables *tables = &isp_dev->tables; 136 int ret; 137 138 tables->load.size = variant->table_load_save_size; 139 ret = sun6i_isp_table_setup(isp_dev, &tables->load); 140 if (ret) 141 return ret; 142 143 tables->save.size = variant->table_load_save_size; 144 ret = sun6i_isp_table_setup(isp_dev, &tables->save); 145 if (ret) 146 return ret; 147 148 tables->lut.size = variant->table_lut_size; 149 ret = sun6i_isp_table_setup(isp_dev, &tables->lut); 150 if (ret) 151 return ret; 152 153 tables->drc.size = variant->table_drc_size; 154 ret = sun6i_isp_table_setup(isp_dev, &tables->drc); 155 if (ret) 156 return ret; 157 158 tables->stats.size = variant->table_stats_size; 159 ret = sun6i_isp_table_setup(isp_dev, &tables->stats); 160 if (ret) 161 return ret; 162 163 return 0; 164} 165 166static void sun6i_isp_tables_cleanup(struct sun6i_isp_device *isp_dev) 167{ 168 struct sun6i_isp_tables *tables = &isp_dev->tables; 169 170 sun6i_isp_table_cleanup(isp_dev, &tables->stats); 171 sun6i_isp_table_cleanup(isp_dev, &tables->drc); 172 sun6i_isp_table_cleanup(isp_dev, &tables->lut); 173 sun6i_isp_table_cleanup(isp_dev, &tables->save); 174 sun6i_isp_table_cleanup(isp_dev, &tables->load); 175} 176 177/* Media */ 178 179static const struct media_device_ops sun6i_isp_media_ops = { 180 .link_notify = v4l2_pipeline_link_notify, 181}; 182 183/* V4L2 */ 184 185static int sun6i_isp_v4l2_setup(struct sun6i_isp_device *isp_dev) 186{ 187 struct sun6i_isp_v4l2 *v4l2 = &isp_dev->v4l2; 188 struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev; 189 struct media_device *media_dev = &v4l2->media_dev; 190 struct device *dev = isp_dev->dev; 191 int ret; 192 193 /* Media Device */ 194 195 strscpy(media_dev->model, SUN6I_ISP_DESCRIPTION, 196 sizeof(media_dev->model)); 197 media_dev->ops = &sun6i_isp_media_ops; 198 media_dev->hw_revision = 0; 199 media_dev->dev = dev; 200 201 media_device_init(media_dev); 202 203 ret = media_device_register(media_dev); 204 if (ret) { 205 dev_err(dev, "failed to register media device\n"); 206 return ret; 207 } 208 209 /* V4L2 Device */ 210 211 v4l2_dev->mdev = media_dev; 212 213 ret = v4l2_device_register(dev, v4l2_dev); 214 if (ret) { 215 dev_err(dev, "failed to register v4l2 device\n"); 216 goto error_media; 217 } 218 219 return 0; 220 221error_media: 222 media_device_unregister(media_dev); 223 media_device_cleanup(media_dev); 224 225 return ret; 226} 227 228static void sun6i_isp_v4l2_cleanup(struct sun6i_isp_device *isp_dev) 229{ 230 struct sun6i_isp_v4l2 *v4l2 = &isp_dev->v4l2; 231 232 media_device_unregister(&v4l2->media_dev); 233 v4l2_device_unregister(&v4l2->v4l2_dev); 234 media_device_cleanup(&v4l2->media_dev); 235} 236 237/* Platform */ 238 239static irqreturn_t sun6i_isp_interrupt(int irq, void *private) 240{ 241 struct sun6i_isp_device *isp_dev = private; 242 struct regmap *regmap = isp_dev->regmap; 243 u32 status = 0, enable = 0; 244 245 regmap_read(regmap, SUN6I_ISP_FE_INT_STA_REG, &status); 246 regmap_read(regmap, SUN6I_ISP_FE_INT_EN_REG, &enable); 247 248 if (!status) 249 return IRQ_NONE; 250 else if (!(status & enable)) 251 goto complete; 252 253 /* 254 * The ISP working cycle starts with a params-load, which makes the 255 * state from the load buffer active. Then it starts processing the 256 * frame and gives a finish interrupt. Soon after that, the next state 257 * coming from the load buffer will be applied for the next frame, 258 * giving a params-load as well. 259 * 260 * Because both frame finish and params-load are received almost 261 * at the same time (one ISR call), handle them in chronology order. 262 */ 263 264 if (status & SUN6I_ISP_FE_INT_STA_FINISH) 265 sun6i_isp_capture_finish(isp_dev); 266 267 if (status & SUN6I_ISP_FE_INT_STA_PARA_LOAD) { 268 sun6i_isp_state_complete(isp_dev); 269 sun6i_isp_state_update(isp_dev, false); 270 } 271 272complete: 273 regmap_write(regmap, SUN6I_ISP_FE_INT_STA_REG, status); 274 275 return IRQ_HANDLED; 276} 277 278static int sun6i_isp_suspend(struct device *dev) 279{ 280 struct sun6i_isp_device *isp_dev = dev_get_drvdata(dev); 281 282 reset_control_assert(isp_dev->reset); 283 clk_disable_unprepare(isp_dev->clock_ram); 284 clk_disable_unprepare(isp_dev->clock_mod); 285 286 return 0; 287} 288 289static int sun6i_isp_resume(struct device *dev) 290{ 291 struct sun6i_isp_device *isp_dev = dev_get_drvdata(dev); 292 int ret; 293 294 ret = reset_control_deassert(isp_dev->reset); 295 if (ret) { 296 dev_err(dev, "failed to deassert reset\n"); 297 return ret; 298 } 299 300 ret = clk_prepare_enable(isp_dev->clock_mod); 301 if (ret) { 302 dev_err(dev, "failed to enable module clock\n"); 303 goto error_reset; 304 } 305 306 ret = clk_prepare_enable(isp_dev->clock_ram); 307 if (ret) { 308 dev_err(dev, "failed to enable ram clock\n"); 309 goto error_clock_mod; 310 } 311 312 return 0; 313 314error_clock_mod: 315 clk_disable_unprepare(isp_dev->clock_mod); 316 317error_reset: 318 reset_control_assert(isp_dev->reset); 319 320 return ret; 321} 322 323static const struct dev_pm_ops sun6i_isp_pm_ops = { 324 .runtime_suspend = sun6i_isp_suspend, 325 .runtime_resume = sun6i_isp_resume, 326}; 327 328static const struct regmap_config sun6i_isp_regmap_config = { 329 .reg_bits = 32, 330 .reg_stride = 4, 331 .val_bits = 32, 332 .max_register = 0x400, 333}; 334 335static int sun6i_isp_resources_setup(struct sun6i_isp_device *isp_dev, 336 struct platform_device *platform_dev) 337{ 338 struct device *dev = isp_dev->dev; 339 void __iomem *io_base; 340 int irq; 341 int ret; 342 343 /* Registers */ 344 345 io_base = devm_platform_ioremap_resource(platform_dev, 0); 346 if (IS_ERR(io_base)) 347 return PTR_ERR(io_base); 348 349 isp_dev->regmap = devm_regmap_init_mmio_clk(dev, "bus", io_base, 350 &sun6i_isp_regmap_config); 351 if (IS_ERR(isp_dev->regmap)) { 352 dev_err(dev, "failed to init register map\n"); 353 return PTR_ERR(isp_dev->regmap); 354 } 355 356 /* Clocks */ 357 358 isp_dev->clock_mod = devm_clk_get(dev, "mod"); 359 if (IS_ERR(isp_dev->clock_mod)) { 360 dev_err(dev, "failed to acquire module clock\n"); 361 return PTR_ERR(isp_dev->clock_mod); 362 } 363 364 isp_dev->clock_ram = devm_clk_get(dev, "ram"); 365 if (IS_ERR(isp_dev->clock_ram)) { 366 dev_err(dev, "failed to acquire ram clock\n"); 367 return PTR_ERR(isp_dev->clock_ram); 368 } 369 370 ret = clk_set_rate_exclusive(isp_dev->clock_mod, 297000000); 371 if (ret) { 372 dev_err(dev, "failed to set mod clock rate\n"); 373 return ret; 374 } 375 376 /* Reset */ 377 378 isp_dev->reset = devm_reset_control_get_shared(dev, NULL); 379 if (IS_ERR(isp_dev->reset)) { 380 dev_err(dev, "failed to acquire reset\n"); 381 ret = PTR_ERR(isp_dev->reset); 382 goto error_clock_rate_exclusive; 383 } 384 385 /* Interrupt */ 386 387 irq = platform_get_irq(platform_dev, 0); 388 if (irq < 0) { 389 dev_err(dev, "failed to get interrupt\n"); 390 ret = -ENXIO; 391 goto error_clock_rate_exclusive; 392 } 393 394 ret = devm_request_irq(dev, irq, sun6i_isp_interrupt, IRQF_SHARED, 395 SUN6I_ISP_NAME, isp_dev); 396 if (ret) { 397 dev_err(dev, "failed to request interrupt\n"); 398 goto error_clock_rate_exclusive; 399 } 400 401 /* Runtime PM */ 402 403 pm_runtime_enable(dev); 404 405 return 0; 406 407error_clock_rate_exclusive: 408 clk_rate_exclusive_put(isp_dev->clock_mod); 409 410 return ret; 411} 412 413static void sun6i_isp_resources_cleanup(struct sun6i_isp_device *isp_dev) 414{ 415 struct device *dev = isp_dev->dev; 416 417 pm_runtime_disable(dev); 418 clk_rate_exclusive_put(isp_dev->clock_mod); 419} 420 421static int sun6i_isp_probe(struct platform_device *platform_dev) 422{ 423 struct sun6i_isp_device *isp_dev; 424 struct device *dev = &platform_dev->dev; 425 const struct sun6i_isp_variant *variant; 426 int ret; 427 428 variant = of_device_get_match_data(dev); 429 if (!variant) 430 return -EINVAL; 431 432 isp_dev = devm_kzalloc(dev, sizeof(*isp_dev), GFP_KERNEL); 433 if (!isp_dev) 434 return -ENOMEM; 435 436 isp_dev->dev = dev; 437 platform_set_drvdata(platform_dev, isp_dev); 438 439 spin_lock_init(&isp_dev->state_lock); 440 441 ret = sun6i_isp_resources_setup(isp_dev, platform_dev); 442 if (ret) 443 return ret; 444 445 ret = sun6i_isp_tables_setup(isp_dev, variant); 446 if (ret) { 447 dev_err(dev, "failed to setup tables\n"); 448 goto error_resources; 449 } 450 451 ret = sun6i_isp_v4l2_setup(isp_dev); 452 if (ret) { 453 dev_err(dev, "failed to setup v4l2\n"); 454 goto error_tables; 455 } 456 457 ret = sun6i_isp_proc_setup(isp_dev); 458 if (ret) { 459 dev_err(dev, "failed to setup proc\n"); 460 goto error_v4l2; 461 } 462 463 ret = sun6i_isp_capture_setup(isp_dev); 464 if (ret) { 465 dev_err(dev, "failed to setup capture\n"); 466 goto error_proc; 467 } 468 469 ret = sun6i_isp_params_setup(isp_dev); 470 if (ret) { 471 dev_err(dev, "failed to setup params\n"); 472 goto error_capture; 473 } 474 475 return 0; 476 477error_capture: 478 sun6i_isp_capture_cleanup(isp_dev); 479 480error_proc: 481 sun6i_isp_proc_cleanup(isp_dev); 482 483error_v4l2: 484 sun6i_isp_v4l2_cleanup(isp_dev); 485 486error_tables: 487 sun6i_isp_tables_cleanup(isp_dev); 488 489error_resources: 490 sun6i_isp_resources_cleanup(isp_dev); 491 492 return ret; 493} 494 495static void sun6i_isp_remove(struct platform_device *platform_dev) 496{ 497 struct sun6i_isp_device *isp_dev = platform_get_drvdata(platform_dev); 498 499 sun6i_isp_params_cleanup(isp_dev); 500 sun6i_isp_capture_cleanup(isp_dev); 501 sun6i_isp_proc_cleanup(isp_dev); 502 sun6i_isp_v4l2_cleanup(isp_dev); 503 sun6i_isp_tables_cleanup(isp_dev); 504 sun6i_isp_resources_cleanup(isp_dev); 505} 506 507/* 508 * History of sun6i-isp: 509 * - sun4i-a10-isp: initial ISP tied to the CSI0 controller, 510 * apparently unused in software implementations; 511 * - sun6i-a31-isp: separate ISP loosely based on sun4i-a10-isp, 512 * adding extra modules and features; 513 * - sun9i-a80-isp: based on sun6i-a31-isp with some register offset changes 514 * and new modules like saturation and cnr; 515 * - sun8i-a23-isp/sun8i-h3-isp: based on sun9i-a80-isp with most modules 516 * related to raw removed; 517 * - sun8i-a83t-isp: based on sun9i-a80-isp with some register offset changes 518 * - sun8i-v3s-isp: based on sun8i-a83t-isp with a new disc module; 519 */ 520 521static const struct sun6i_isp_variant sun8i_v3s_isp_variant = { 522 .table_load_save_size = 0x1000, 523 .table_lut_size = 0xe00, 524 .table_drc_size = 0x600, 525 .table_stats_size = 0x2100, 526}; 527 528static const struct of_device_id sun6i_isp_of_match[] = { 529 { 530 .compatible = "allwinner,sun8i-v3s-isp", 531 .data = &sun8i_v3s_isp_variant, 532 }, 533 {}, 534}; 535 536MODULE_DEVICE_TABLE(of, sun6i_isp_of_match); 537 538static struct platform_driver sun6i_isp_platform_driver = { 539 .probe = sun6i_isp_probe, 540 .remove_new = sun6i_isp_remove, 541 .driver = { 542 .name = SUN6I_ISP_NAME, 543 .of_match_table = sun6i_isp_of_match, 544 .pm = &sun6i_isp_pm_ops, 545 }, 546}; 547 548module_platform_driver(sun6i_isp_platform_driver); 549 550MODULE_DESCRIPTION("Allwinner A31 Image Signal Processor driver"); 551MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>"); 552MODULE_LICENSE("GPL"); 553