18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * VPDMA helper library 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2013 Texas Instruments Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * David Griego, <dagriego@biglakesoftware.com> 88c2ecf20Sopenharmony_ci * Dale Farnsworth, <dale@farnsworth.org> 98c2ecf20Sopenharmony_ci * Archit Taneja, <archit@ti.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 148c2ecf20Sopenharmony_ci#include <linux/err.h> 158c2ecf20Sopenharmony_ci#include <linux/firmware.h> 168c2ecf20Sopenharmony_ci#include <linux/io.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 198c2ecf20Sopenharmony_ci#include <linux/sched.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "vpdma.h" 248c2ecf20Sopenharmony_ci#include "vpdma_priv.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define VPDMA_FIRMWARE "vpdma-1b8.bin" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ciconst struct vpdma_data_format vpdma_yuv_fmts[] = { 298c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_Y444] = { 308c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_YUV, 318c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_Y444, 328c2ecf20Sopenharmony_ci .depth = 8, 338c2ecf20Sopenharmony_ci }, 348c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_Y422] = { 358c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_YUV, 368c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_Y422, 378c2ecf20Sopenharmony_ci .depth = 8, 388c2ecf20Sopenharmony_ci }, 398c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_Y420] = { 408c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_YUV, 418c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_Y420, 428c2ecf20Sopenharmony_ci .depth = 8, 438c2ecf20Sopenharmony_ci }, 448c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_C444] = { 458c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_YUV, 468c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_C444, 478c2ecf20Sopenharmony_ci .depth = 8, 488c2ecf20Sopenharmony_ci }, 498c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_C422] = { 508c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_YUV, 518c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_C422, 528c2ecf20Sopenharmony_ci .depth = 8, 538c2ecf20Sopenharmony_ci }, 548c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_C420] = { 558c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_YUV, 568c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_C420, 578c2ecf20Sopenharmony_ci .depth = 4, 588c2ecf20Sopenharmony_ci }, 598c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_CB420] = { 608c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_YUV, 618c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_CB420, 628c2ecf20Sopenharmony_ci .depth = 4, 638c2ecf20Sopenharmony_ci }, 648c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_YCR422] = { 658c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_YUV, 668c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_YCR422, 678c2ecf20Sopenharmony_ci .depth = 16, 688c2ecf20Sopenharmony_ci }, 698c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_YC444] = { 708c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_YUV, 718c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_YC444, 728c2ecf20Sopenharmony_ci .depth = 24, 738c2ecf20Sopenharmony_ci }, 748c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_CRY422] = { 758c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_YUV, 768c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_CRY422, 778c2ecf20Sopenharmony_ci .depth = 16, 788c2ecf20Sopenharmony_ci }, 798c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_CBY422] = { 808c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_YUV, 818c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_CBY422, 828c2ecf20Sopenharmony_ci .depth = 16, 838c2ecf20Sopenharmony_ci }, 848c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_YCB422] = { 858c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_YUV, 868c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_YCB422, 878c2ecf20Sopenharmony_ci .depth = 16, 888c2ecf20Sopenharmony_ci }, 898c2ecf20Sopenharmony_ci}; 908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_yuv_fmts); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ciconst struct vpdma_data_format vpdma_rgb_fmts[] = { 938c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_RGB565] = { 948c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 958c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_RGB16_565, 968c2ecf20Sopenharmony_ci .depth = 16, 978c2ecf20Sopenharmony_ci }, 988c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_ARGB16_1555] = { 998c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1008c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_ARGB_1555, 1018c2ecf20Sopenharmony_ci .depth = 16, 1028c2ecf20Sopenharmony_ci }, 1038c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_ARGB16] = { 1048c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1058c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_ARGB_4444, 1068c2ecf20Sopenharmony_ci .depth = 16, 1078c2ecf20Sopenharmony_ci }, 1088c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_RGBA16_5551] = { 1098c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1108c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_RGBA_5551, 1118c2ecf20Sopenharmony_ci .depth = 16, 1128c2ecf20Sopenharmony_ci }, 1138c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_RGBA16] = { 1148c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1158c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_RGBA_4444, 1168c2ecf20Sopenharmony_ci .depth = 16, 1178c2ecf20Sopenharmony_ci }, 1188c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_ARGB24] = { 1198c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1208c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_ARGB24_6666, 1218c2ecf20Sopenharmony_ci .depth = 24, 1228c2ecf20Sopenharmony_ci }, 1238c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_RGB24] = { 1248c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1258c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_RGB24_888, 1268c2ecf20Sopenharmony_ci .depth = 24, 1278c2ecf20Sopenharmony_ci }, 1288c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_ARGB32] = { 1298c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1308c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_ARGB32_8888, 1318c2ecf20Sopenharmony_ci .depth = 32, 1328c2ecf20Sopenharmony_ci }, 1338c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_RGBA24] = { 1348c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1358c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_RGBA24_6666, 1368c2ecf20Sopenharmony_ci .depth = 24, 1378c2ecf20Sopenharmony_ci }, 1388c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_RGBA32] = { 1398c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1408c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_RGBA32_8888, 1418c2ecf20Sopenharmony_ci .depth = 32, 1428c2ecf20Sopenharmony_ci }, 1438c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_BGR565] = { 1448c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1458c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_BGR16_565, 1468c2ecf20Sopenharmony_ci .depth = 16, 1478c2ecf20Sopenharmony_ci }, 1488c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_ABGR16_1555] = { 1498c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1508c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_ABGR_1555, 1518c2ecf20Sopenharmony_ci .depth = 16, 1528c2ecf20Sopenharmony_ci }, 1538c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_ABGR16] = { 1548c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1558c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_ABGR_4444, 1568c2ecf20Sopenharmony_ci .depth = 16, 1578c2ecf20Sopenharmony_ci }, 1588c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_BGRA16_5551] = { 1598c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1608c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_BGRA_5551, 1618c2ecf20Sopenharmony_ci .depth = 16, 1628c2ecf20Sopenharmony_ci }, 1638c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_BGRA16] = { 1648c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1658c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_BGRA_4444, 1668c2ecf20Sopenharmony_ci .depth = 16, 1678c2ecf20Sopenharmony_ci }, 1688c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_ABGR24] = { 1698c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1708c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_ABGR24_6666, 1718c2ecf20Sopenharmony_ci .depth = 24, 1728c2ecf20Sopenharmony_ci }, 1738c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_BGR24] = { 1748c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1758c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_BGR24_888, 1768c2ecf20Sopenharmony_ci .depth = 24, 1778c2ecf20Sopenharmony_ci }, 1788c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_ABGR32] = { 1798c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1808c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_ABGR32_8888, 1818c2ecf20Sopenharmony_ci .depth = 32, 1828c2ecf20Sopenharmony_ci }, 1838c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_BGRA24] = { 1848c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1858c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_BGRA24_6666, 1868c2ecf20Sopenharmony_ci .depth = 24, 1878c2ecf20Sopenharmony_ci }, 1888c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_BGRA32] = { 1898c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_RGB, 1908c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_BGRA32_8888, 1918c2ecf20Sopenharmony_ci .depth = 32, 1928c2ecf20Sopenharmony_ci }, 1938c2ecf20Sopenharmony_ci}; 1948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_rgb_fmts); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* 1978c2ecf20Sopenharmony_ci * To handle RAW format we are re-using the CBY422 1988c2ecf20Sopenharmony_ci * vpdma data type so that we use the vpdma to re-order 1998c2ecf20Sopenharmony_ci * the incoming bytes, as the parser assumes that the 2008c2ecf20Sopenharmony_ci * first byte presented on the bus is the MSB of a 2 2018c2ecf20Sopenharmony_ci * bytes value. 2028c2ecf20Sopenharmony_ci * RAW8 handles from 1 to 8 bits 2038c2ecf20Sopenharmony_ci * RAW16 handles from 9 to 16 bits 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_ciconst struct vpdma_data_format vpdma_raw_fmts[] = { 2068c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_RAW8] = { 2078c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_YUV, 2088c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_CBY422, 2098c2ecf20Sopenharmony_ci .depth = 8, 2108c2ecf20Sopenharmony_ci }, 2118c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_RAW16] = { 2128c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_YUV, 2138c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_CBY422, 2148c2ecf20Sopenharmony_ci .depth = 16, 2158c2ecf20Sopenharmony_ci }, 2168c2ecf20Sopenharmony_ci}; 2178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_raw_fmts); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ciconst struct vpdma_data_format vpdma_misc_fmts[] = { 2208c2ecf20Sopenharmony_ci [VPDMA_DATA_FMT_MV] = { 2218c2ecf20Sopenharmony_ci .type = VPDMA_DATA_FMT_TYPE_MISC, 2228c2ecf20Sopenharmony_ci .data_type = DATA_TYPE_MV, 2238c2ecf20Sopenharmony_ci .depth = 4, 2248c2ecf20Sopenharmony_ci }, 2258c2ecf20Sopenharmony_ci}; 2268c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_misc_fmts); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistruct vpdma_channel_info { 2298c2ecf20Sopenharmony_ci int num; /* VPDMA channel number */ 2308c2ecf20Sopenharmony_ci int cstat_offset; /* client CSTAT register offset */ 2318c2ecf20Sopenharmony_ci}; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic const struct vpdma_channel_info chan_info[] = { 2348c2ecf20Sopenharmony_ci [VPE_CHAN_LUMA1_IN] = { 2358c2ecf20Sopenharmony_ci .num = VPE_CHAN_NUM_LUMA1_IN, 2368c2ecf20Sopenharmony_ci .cstat_offset = VPDMA_DEI_LUMA1_CSTAT, 2378c2ecf20Sopenharmony_ci }, 2388c2ecf20Sopenharmony_ci [VPE_CHAN_CHROMA1_IN] = { 2398c2ecf20Sopenharmony_ci .num = VPE_CHAN_NUM_CHROMA1_IN, 2408c2ecf20Sopenharmony_ci .cstat_offset = VPDMA_DEI_CHROMA1_CSTAT, 2418c2ecf20Sopenharmony_ci }, 2428c2ecf20Sopenharmony_ci [VPE_CHAN_LUMA2_IN] = { 2438c2ecf20Sopenharmony_ci .num = VPE_CHAN_NUM_LUMA2_IN, 2448c2ecf20Sopenharmony_ci .cstat_offset = VPDMA_DEI_LUMA2_CSTAT, 2458c2ecf20Sopenharmony_ci }, 2468c2ecf20Sopenharmony_ci [VPE_CHAN_CHROMA2_IN] = { 2478c2ecf20Sopenharmony_ci .num = VPE_CHAN_NUM_CHROMA2_IN, 2488c2ecf20Sopenharmony_ci .cstat_offset = VPDMA_DEI_CHROMA2_CSTAT, 2498c2ecf20Sopenharmony_ci }, 2508c2ecf20Sopenharmony_ci [VPE_CHAN_LUMA3_IN] = { 2518c2ecf20Sopenharmony_ci .num = VPE_CHAN_NUM_LUMA3_IN, 2528c2ecf20Sopenharmony_ci .cstat_offset = VPDMA_DEI_LUMA3_CSTAT, 2538c2ecf20Sopenharmony_ci }, 2548c2ecf20Sopenharmony_ci [VPE_CHAN_CHROMA3_IN] = { 2558c2ecf20Sopenharmony_ci .num = VPE_CHAN_NUM_CHROMA3_IN, 2568c2ecf20Sopenharmony_ci .cstat_offset = VPDMA_DEI_CHROMA3_CSTAT, 2578c2ecf20Sopenharmony_ci }, 2588c2ecf20Sopenharmony_ci [VPE_CHAN_MV_IN] = { 2598c2ecf20Sopenharmony_ci .num = VPE_CHAN_NUM_MV_IN, 2608c2ecf20Sopenharmony_ci .cstat_offset = VPDMA_DEI_MV_IN_CSTAT, 2618c2ecf20Sopenharmony_ci }, 2628c2ecf20Sopenharmony_ci [VPE_CHAN_MV_OUT] = { 2638c2ecf20Sopenharmony_ci .num = VPE_CHAN_NUM_MV_OUT, 2648c2ecf20Sopenharmony_ci .cstat_offset = VPDMA_DEI_MV_OUT_CSTAT, 2658c2ecf20Sopenharmony_ci }, 2668c2ecf20Sopenharmony_ci [VPE_CHAN_LUMA_OUT] = { 2678c2ecf20Sopenharmony_ci .num = VPE_CHAN_NUM_LUMA_OUT, 2688c2ecf20Sopenharmony_ci .cstat_offset = VPDMA_VIP_UP_Y_CSTAT, 2698c2ecf20Sopenharmony_ci }, 2708c2ecf20Sopenharmony_ci [VPE_CHAN_CHROMA_OUT] = { 2718c2ecf20Sopenharmony_ci .num = VPE_CHAN_NUM_CHROMA_OUT, 2728c2ecf20Sopenharmony_ci .cstat_offset = VPDMA_VIP_UP_UV_CSTAT, 2738c2ecf20Sopenharmony_ci }, 2748c2ecf20Sopenharmony_ci [VPE_CHAN_RGB_OUT] = { 2758c2ecf20Sopenharmony_ci .num = VPE_CHAN_NUM_RGB_OUT, 2768c2ecf20Sopenharmony_ci .cstat_offset = VPDMA_VIP_UP_Y_CSTAT, 2778c2ecf20Sopenharmony_ci }, 2788c2ecf20Sopenharmony_ci}; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic u32 read_reg(struct vpdma_data *vpdma, int offset) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci return ioread32(vpdma->base + offset); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic void write_reg(struct vpdma_data *vpdma, int offset, u32 value) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci iowrite32(value, vpdma->base + offset); 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic int read_field_reg(struct vpdma_data *vpdma, int offset, 2918c2ecf20Sopenharmony_ci u32 mask, int shift) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci return (read_reg(vpdma, offset) & (mask << shift)) >> shift; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic void write_field_reg(struct vpdma_data *vpdma, int offset, u32 field, 2978c2ecf20Sopenharmony_ci u32 mask, int shift) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci u32 val = read_reg(vpdma, offset); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci val &= ~(mask << shift); 3028c2ecf20Sopenharmony_ci val |= (field & mask) << shift; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci write_reg(vpdma, offset, val); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_civoid vpdma_dump_regs(struct vpdma_data *vpdma) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct device *dev = &vpdma->pdev->dev; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci#define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, read_reg(vpdma, VPDMA_##r)) 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci dev_dbg(dev, "VPDMA Registers:\n"); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci DUMPREG(PID); 3168c2ecf20Sopenharmony_ci DUMPREG(LIST_ADDR); 3178c2ecf20Sopenharmony_ci DUMPREG(LIST_ATTR); 3188c2ecf20Sopenharmony_ci DUMPREG(LIST_STAT_SYNC); 3198c2ecf20Sopenharmony_ci DUMPREG(BG_RGB); 3208c2ecf20Sopenharmony_ci DUMPREG(BG_YUV); 3218c2ecf20Sopenharmony_ci DUMPREG(SETUP); 3228c2ecf20Sopenharmony_ci DUMPREG(MAX_SIZE1); 3238c2ecf20Sopenharmony_ci DUMPREG(MAX_SIZE2); 3248c2ecf20Sopenharmony_ci DUMPREG(MAX_SIZE3); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* 3278c2ecf20Sopenharmony_ci * dumping registers of only group0 and group3, because VPE channels 3288c2ecf20Sopenharmony_ci * lie within group0 and group3 registers 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_ci DUMPREG(INT_CHAN_STAT(0)); 3318c2ecf20Sopenharmony_ci DUMPREG(INT_CHAN_MASK(0)); 3328c2ecf20Sopenharmony_ci DUMPREG(INT_CHAN_STAT(3)); 3338c2ecf20Sopenharmony_ci DUMPREG(INT_CHAN_MASK(3)); 3348c2ecf20Sopenharmony_ci DUMPREG(INT_CLIENT0_STAT); 3358c2ecf20Sopenharmony_ci DUMPREG(INT_CLIENT0_MASK); 3368c2ecf20Sopenharmony_ci DUMPREG(INT_CLIENT1_STAT); 3378c2ecf20Sopenharmony_ci DUMPREG(INT_CLIENT1_MASK); 3388c2ecf20Sopenharmony_ci DUMPREG(INT_LIST0_STAT); 3398c2ecf20Sopenharmony_ci DUMPREG(INT_LIST0_MASK); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* 3428c2ecf20Sopenharmony_ci * these are registers specific to VPE clients, we can make this 3438c2ecf20Sopenharmony_ci * function dump client registers specific to VPE or VIP based on 3448c2ecf20Sopenharmony_ci * who is using it 3458c2ecf20Sopenharmony_ci */ 3468c2ecf20Sopenharmony_ci DUMPREG(DEI_CHROMA1_CSTAT); 3478c2ecf20Sopenharmony_ci DUMPREG(DEI_LUMA1_CSTAT); 3488c2ecf20Sopenharmony_ci DUMPREG(DEI_CHROMA2_CSTAT); 3498c2ecf20Sopenharmony_ci DUMPREG(DEI_LUMA2_CSTAT); 3508c2ecf20Sopenharmony_ci DUMPREG(DEI_CHROMA3_CSTAT); 3518c2ecf20Sopenharmony_ci DUMPREG(DEI_LUMA3_CSTAT); 3528c2ecf20Sopenharmony_ci DUMPREG(DEI_MV_IN_CSTAT); 3538c2ecf20Sopenharmony_ci DUMPREG(DEI_MV_OUT_CSTAT); 3548c2ecf20Sopenharmony_ci DUMPREG(VIP_UP_Y_CSTAT); 3558c2ecf20Sopenharmony_ci DUMPREG(VIP_UP_UV_CSTAT); 3568c2ecf20Sopenharmony_ci DUMPREG(VPI_CTL_CSTAT); 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_dump_regs); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci/* 3618c2ecf20Sopenharmony_ci * Allocate a DMA buffer 3628c2ecf20Sopenharmony_ci */ 3638c2ecf20Sopenharmony_ciint vpdma_alloc_desc_buf(struct vpdma_buf *buf, size_t size) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci buf->size = size; 3668c2ecf20Sopenharmony_ci buf->mapped = false; 3678c2ecf20Sopenharmony_ci buf->addr = kzalloc(size, GFP_KERNEL); 3688c2ecf20Sopenharmony_ci if (!buf->addr) 3698c2ecf20Sopenharmony_ci return -ENOMEM; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci WARN_ON(((unsigned long)buf->addr & VPDMA_DESC_ALIGN) != 0); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci return 0; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_alloc_desc_buf); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_civoid vpdma_free_desc_buf(struct vpdma_buf *buf) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci WARN_ON(buf->mapped); 3808c2ecf20Sopenharmony_ci kfree(buf->addr); 3818c2ecf20Sopenharmony_ci buf->addr = NULL; 3828c2ecf20Sopenharmony_ci buf->size = 0; 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_free_desc_buf); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci/* 3878c2ecf20Sopenharmony_ci * map descriptor/payload DMA buffer, enabling DMA access 3888c2ecf20Sopenharmony_ci */ 3898c2ecf20Sopenharmony_ciint vpdma_map_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct device *dev = &vpdma->pdev->dev; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci WARN_ON(buf->mapped); 3948c2ecf20Sopenharmony_ci buf->dma_addr = dma_map_single(dev, buf->addr, buf->size, 3958c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 3968c2ecf20Sopenharmony_ci if (dma_mapping_error(dev, buf->dma_addr)) { 3978c2ecf20Sopenharmony_ci dev_err(dev, "failed to map buffer\n"); 3988c2ecf20Sopenharmony_ci return -EINVAL; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci buf->mapped = true; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci return 0; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_map_desc_buf); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci/* 4088c2ecf20Sopenharmony_ci * unmap descriptor/payload DMA buffer, disabling DMA access and 4098c2ecf20Sopenharmony_ci * allowing the main processor to access the data 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_civoid vpdma_unmap_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci struct device *dev = &vpdma->pdev->dev; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (buf->mapped) 4168c2ecf20Sopenharmony_ci dma_unmap_single(dev, buf->dma_addr, buf->size, 4178c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci buf->mapped = false; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_unmap_desc_buf); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci/* 4248c2ecf20Sopenharmony_ci * Cleanup all pending descriptors of a list 4258c2ecf20Sopenharmony_ci * First, stop the current list being processed. 4268c2ecf20Sopenharmony_ci * If the VPDMA was busy, this step makes vpdma to accept post lists. 4278c2ecf20Sopenharmony_ci * To cleanup the internal FSM, post abort list descriptor for all the 4288c2ecf20Sopenharmony_ci * channels from @channels array of size @size. 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_ciint vpdma_list_cleanup(struct vpdma_data *vpdma, int list_num, 4318c2ecf20Sopenharmony_ci int *channels, int size) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct vpdma_desc_list abort_list; 4348c2ecf20Sopenharmony_ci int i, ret, timeout = 500; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci write_reg(vpdma, VPDMA_LIST_ATTR, 4378c2ecf20Sopenharmony_ci (list_num << VPDMA_LIST_NUM_SHFT) | 4388c2ecf20Sopenharmony_ci (1 << VPDMA_LIST_STOP_SHFT)); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (size <= 0 || !channels) 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci ret = vpdma_create_desc_list(&abort_list, 4448c2ecf20Sopenharmony_ci size * sizeof(struct vpdma_dtd), VPDMA_LIST_TYPE_NORMAL); 4458c2ecf20Sopenharmony_ci if (ret) 4468c2ecf20Sopenharmony_ci return ret; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) 4498c2ecf20Sopenharmony_ci vpdma_add_abort_channel_ctd(&abort_list, channels[i]); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci ret = vpdma_map_desc_buf(vpdma, &abort_list.buf); 4528c2ecf20Sopenharmony_ci if (ret) 4538c2ecf20Sopenharmony_ci goto free_desc; 4548c2ecf20Sopenharmony_ci ret = vpdma_submit_descs(vpdma, &abort_list, list_num); 4558c2ecf20Sopenharmony_ci if (ret) 4568c2ecf20Sopenharmony_ci goto unmap_desc; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci while (vpdma_list_busy(vpdma, list_num) && --timeout) 4598c2ecf20Sopenharmony_ci ; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (timeout == 0) { 4628c2ecf20Sopenharmony_ci dev_err(&vpdma->pdev->dev, "Timed out cleaning up VPDMA list\n"); 4638c2ecf20Sopenharmony_ci ret = -EBUSY; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ciunmap_desc: 4678c2ecf20Sopenharmony_ci vpdma_unmap_desc_buf(vpdma, &abort_list.buf); 4688c2ecf20Sopenharmony_cifree_desc: 4698c2ecf20Sopenharmony_ci vpdma_free_desc_buf(&abort_list.buf); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci return ret; 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_list_cleanup); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci/* 4768c2ecf20Sopenharmony_ci * create a descriptor list, the user of this list will append configuration, 4778c2ecf20Sopenharmony_ci * control and data descriptors to this list, this list will be submitted to 4788c2ecf20Sopenharmony_ci * VPDMA. VPDMA's list parser will go through each descriptor and perform the 4798c2ecf20Sopenharmony_ci * required DMA operations 4808c2ecf20Sopenharmony_ci */ 4818c2ecf20Sopenharmony_ciint vpdma_create_desc_list(struct vpdma_desc_list *list, size_t size, int type) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci int r; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci r = vpdma_alloc_desc_buf(&list->buf, size); 4868c2ecf20Sopenharmony_ci if (r) 4878c2ecf20Sopenharmony_ci return r; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci list->next = list->buf.addr; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci list->type = type; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci return 0; 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_create_desc_list); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci/* 4988c2ecf20Sopenharmony_ci * once a descriptor list is parsed by VPDMA, we reset the list by emptying it, 4998c2ecf20Sopenharmony_ci * to allow new descriptors to be added to the list. 5008c2ecf20Sopenharmony_ci */ 5018c2ecf20Sopenharmony_civoid vpdma_reset_desc_list(struct vpdma_desc_list *list) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci list->next = list->buf.addr; 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_reset_desc_list); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci/* 5088c2ecf20Sopenharmony_ci * free the buffer allocated for the VPDMA descriptor list, this should be 5098c2ecf20Sopenharmony_ci * called when the user doesn't want to use VPDMA any more. 5108c2ecf20Sopenharmony_ci */ 5118c2ecf20Sopenharmony_civoid vpdma_free_desc_list(struct vpdma_desc_list *list) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci vpdma_free_desc_buf(&list->buf); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci list->next = NULL; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_free_desc_list); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cibool vpdma_list_busy(struct vpdma_data *vpdma, int list_num) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci return read_reg(vpdma, VPDMA_LIST_STAT_SYNC) & BIT(list_num + 16); 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_list_busy); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci/* 5268c2ecf20Sopenharmony_ci * submit a list of DMA descriptors to the VPE VPDMA, do not wait for completion 5278c2ecf20Sopenharmony_ci */ 5288c2ecf20Sopenharmony_ciint vpdma_submit_descs(struct vpdma_data *vpdma, 5298c2ecf20Sopenharmony_ci struct vpdma_desc_list *list, int list_num) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci int list_size; 5328c2ecf20Sopenharmony_ci unsigned long flags; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (vpdma_list_busy(vpdma, list_num)) 5358c2ecf20Sopenharmony_ci return -EBUSY; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* 16-byte granularity */ 5388c2ecf20Sopenharmony_ci list_size = (list->next - list->buf.addr) >> 4; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci spin_lock_irqsave(&vpdma->lock, flags); 5418c2ecf20Sopenharmony_ci write_reg(vpdma, VPDMA_LIST_ADDR, (u32) list->buf.dma_addr); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci write_reg(vpdma, VPDMA_LIST_ATTR, 5448c2ecf20Sopenharmony_ci (list_num << VPDMA_LIST_NUM_SHFT) | 5458c2ecf20Sopenharmony_ci (list->type << VPDMA_LIST_TYPE_SHFT) | 5468c2ecf20Sopenharmony_ci list_size); 5478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vpdma->lock, flags); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci return 0; 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_submit_descs); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic void dump_dtd(struct vpdma_dtd *dtd); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_civoid vpdma_update_dma_addr(struct vpdma_data *vpdma, 5568c2ecf20Sopenharmony_ci struct vpdma_desc_list *list, dma_addr_t dma_addr, 5578c2ecf20Sopenharmony_ci void *write_dtd, int drop, int idx) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct vpdma_dtd *dtd = list->buf.addr; 5608c2ecf20Sopenharmony_ci dma_addr_t write_desc_addr; 5618c2ecf20Sopenharmony_ci int offset; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci dtd += idx; 5648c2ecf20Sopenharmony_ci vpdma_unmap_desc_buf(vpdma, &list->buf); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci dtd->start_addr = dma_addr; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci /* Calculate write address from the offset of write_dtd from start 5698c2ecf20Sopenharmony_ci * of the list->buf 5708c2ecf20Sopenharmony_ci */ 5718c2ecf20Sopenharmony_ci offset = (void *)write_dtd - list->buf.addr; 5728c2ecf20Sopenharmony_ci write_desc_addr = list->buf.dma_addr + offset; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (drop) 5758c2ecf20Sopenharmony_ci dtd->desc_write_addr = dtd_desc_write_addr(write_desc_addr, 5768c2ecf20Sopenharmony_ci 1, 1, 0); 5778c2ecf20Sopenharmony_ci else 5788c2ecf20Sopenharmony_ci dtd->desc_write_addr = dtd_desc_write_addr(write_desc_addr, 5798c2ecf20Sopenharmony_ci 1, 0, 0); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci vpdma_map_desc_buf(vpdma, &list->buf); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci dump_dtd(dtd); 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_update_dma_addr); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_civoid vpdma_set_max_size(struct vpdma_data *vpdma, int reg_addr, 5888c2ecf20Sopenharmony_ci u32 width, u32 height) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci if (reg_addr != VPDMA_MAX_SIZE1 && reg_addr != VPDMA_MAX_SIZE2 && 5918c2ecf20Sopenharmony_ci reg_addr != VPDMA_MAX_SIZE3) 5928c2ecf20Sopenharmony_ci reg_addr = VPDMA_MAX_SIZE1; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci write_field_reg(vpdma, reg_addr, width - 1, 5958c2ecf20Sopenharmony_ci VPDMA_MAX_SIZE_WIDTH_MASK, VPDMA_MAX_SIZE_WIDTH_SHFT); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci write_field_reg(vpdma, reg_addr, height - 1, 5988c2ecf20Sopenharmony_ci VPDMA_MAX_SIZE_HEIGHT_MASK, VPDMA_MAX_SIZE_HEIGHT_SHFT); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_set_max_size); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic void dump_cfd(struct vpdma_cfd *cfd) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci int class; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci class = cfd_get_class(cfd); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci pr_debug("config descriptor of payload class: %s\n", 6108c2ecf20Sopenharmony_ci class == CFD_CLS_BLOCK ? "simple block" : 6118c2ecf20Sopenharmony_ci "address data block"); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci if (class == CFD_CLS_BLOCK) 6148c2ecf20Sopenharmony_ci pr_debug("word0: dst_addr_offset = 0x%08x\n", 6158c2ecf20Sopenharmony_ci cfd->dest_addr_offset); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (class == CFD_CLS_BLOCK) 6188c2ecf20Sopenharmony_ci pr_debug("word1: num_data_wrds = %d\n", cfd->block_len); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci pr_debug("word2: payload_addr = 0x%08x\n", cfd->payload_addr); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci pr_debug("word3: pkt_type = %d, direct = %d, class = %d, dest = %d, payload_len = %d\n", 6238c2ecf20Sopenharmony_ci cfd_get_pkt_type(cfd), 6248c2ecf20Sopenharmony_ci cfd_get_direct(cfd), class, cfd_get_dest(cfd), 6258c2ecf20Sopenharmony_ci cfd_get_payload_len(cfd)); 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci/* 6298c2ecf20Sopenharmony_ci * append a configuration descriptor to the given descriptor list, where the 6308c2ecf20Sopenharmony_ci * payload is in the form of a simple data block specified in the descriptor 6318c2ecf20Sopenharmony_ci * header, this is used to upload scaler coefficients to the scaler module 6328c2ecf20Sopenharmony_ci */ 6338c2ecf20Sopenharmony_civoid vpdma_add_cfd_block(struct vpdma_desc_list *list, int client, 6348c2ecf20Sopenharmony_ci struct vpdma_buf *blk, u32 dest_offset) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct vpdma_cfd *cfd; 6378c2ecf20Sopenharmony_ci int len = blk->size; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci WARN_ON(blk->dma_addr & VPDMA_DESC_ALIGN); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci cfd = list->next; 6428c2ecf20Sopenharmony_ci WARN_ON((void *)(cfd + 1) > (list->buf.addr + list->buf.size)); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci cfd->dest_addr_offset = dest_offset; 6458c2ecf20Sopenharmony_ci cfd->block_len = len; 6468c2ecf20Sopenharmony_ci cfd->payload_addr = (u32) blk->dma_addr; 6478c2ecf20Sopenharmony_ci cfd->ctl_payload_len = cfd_pkt_payload_len(CFD_INDIRECT, CFD_CLS_BLOCK, 6488c2ecf20Sopenharmony_ci client, len >> 4); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci list->next = cfd + 1; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci dump_cfd(cfd); 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_add_cfd_block); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci/* 6578c2ecf20Sopenharmony_ci * append a configuration descriptor to the given descriptor list, where the 6588c2ecf20Sopenharmony_ci * payload is in the address data block format, this is used to a configure a 6598c2ecf20Sopenharmony_ci * discontiguous set of MMRs 6608c2ecf20Sopenharmony_ci */ 6618c2ecf20Sopenharmony_civoid vpdma_add_cfd_adb(struct vpdma_desc_list *list, int client, 6628c2ecf20Sopenharmony_ci struct vpdma_buf *adb) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci struct vpdma_cfd *cfd; 6658c2ecf20Sopenharmony_ci unsigned int len = adb->size; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci WARN_ON(len & VPDMA_ADB_SIZE_ALIGN); 6688c2ecf20Sopenharmony_ci WARN_ON(adb->dma_addr & VPDMA_DESC_ALIGN); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci cfd = list->next; 6718c2ecf20Sopenharmony_ci BUG_ON((void *)(cfd + 1) > (list->buf.addr + list->buf.size)); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci cfd->w0 = 0; 6748c2ecf20Sopenharmony_ci cfd->w1 = 0; 6758c2ecf20Sopenharmony_ci cfd->payload_addr = (u32) adb->dma_addr; 6768c2ecf20Sopenharmony_ci cfd->ctl_payload_len = cfd_pkt_payload_len(CFD_INDIRECT, CFD_CLS_ADB, 6778c2ecf20Sopenharmony_ci client, len >> 4); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci list->next = cfd + 1; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci dump_cfd(cfd); 6828c2ecf20Sopenharmony_ci}; 6838c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_add_cfd_adb); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci/* 6868c2ecf20Sopenharmony_ci * control descriptor format change based on what type of control descriptor it 6878c2ecf20Sopenharmony_ci * is, we only use 'sync on channel' control descriptors for now, so assume it's 6888c2ecf20Sopenharmony_ci * that 6898c2ecf20Sopenharmony_ci */ 6908c2ecf20Sopenharmony_cistatic void dump_ctd(struct vpdma_ctd *ctd) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci pr_debug("control descriptor\n"); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci pr_debug("word3: pkt_type = %d, source = %d, ctl_type = %d\n", 6958c2ecf20Sopenharmony_ci ctd_get_pkt_type(ctd), ctd_get_source(ctd), ctd_get_ctl(ctd)); 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci/* 6998c2ecf20Sopenharmony_ci * append a 'sync on channel' type control descriptor to the given descriptor 7008c2ecf20Sopenharmony_ci * list, this descriptor stalls the VPDMA list till the time DMA is completed 7018c2ecf20Sopenharmony_ci * on the specified channel 7028c2ecf20Sopenharmony_ci */ 7038c2ecf20Sopenharmony_civoid vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list, 7048c2ecf20Sopenharmony_ci enum vpdma_channel chan) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci struct vpdma_ctd *ctd; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci ctd = list->next; 7098c2ecf20Sopenharmony_ci WARN_ON((void *)(ctd + 1) > (list->buf.addr + list->buf.size)); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci ctd->w0 = 0; 7128c2ecf20Sopenharmony_ci ctd->w1 = 0; 7138c2ecf20Sopenharmony_ci ctd->w2 = 0; 7148c2ecf20Sopenharmony_ci ctd->type_source_ctl = ctd_type_source_ctl(chan_info[chan].num, 7158c2ecf20Sopenharmony_ci CTD_TYPE_SYNC_ON_CHANNEL); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci list->next = ctd + 1; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci dump_ctd(ctd); 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_add_sync_on_channel_ctd); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci/* 7248c2ecf20Sopenharmony_ci * append an 'abort_channel' type control descriptor to the given descriptor 7258c2ecf20Sopenharmony_ci * list, this descriptor aborts any DMA transaction happening using the 7268c2ecf20Sopenharmony_ci * specified channel 7278c2ecf20Sopenharmony_ci */ 7288c2ecf20Sopenharmony_civoid vpdma_add_abort_channel_ctd(struct vpdma_desc_list *list, 7298c2ecf20Sopenharmony_ci int chan_num) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci struct vpdma_ctd *ctd; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci ctd = list->next; 7348c2ecf20Sopenharmony_ci WARN_ON((void *)(ctd + 1) > (list->buf.addr + list->buf.size)); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci ctd->w0 = 0; 7378c2ecf20Sopenharmony_ci ctd->w1 = 0; 7388c2ecf20Sopenharmony_ci ctd->w2 = 0; 7398c2ecf20Sopenharmony_ci ctd->type_source_ctl = ctd_type_source_ctl(chan_num, 7408c2ecf20Sopenharmony_ci CTD_TYPE_ABORT_CHANNEL); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci list->next = ctd + 1; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci dump_ctd(ctd); 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_add_abort_channel_ctd); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cistatic void dump_dtd(struct vpdma_dtd *dtd) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci int dir, chan; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci dir = dtd_get_dir(dtd); 7538c2ecf20Sopenharmony_ci chan = dtd_get_chan(dtd); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci pr_debug("%s data transfer descriptor for channel %d\n", 7568c2ecf20Sopenharmony_ci dir == DTD_DIR_OUT ? "outbound" : "inbound", chan); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci pr_debug("word0: data_type = %d, notify = %d, field = %d, 1D = %d, even_ln_skp = %d, odd_ln_skp = %d, line_stride = %d\n", 7598c2ecf20Sopenharmony_ci dtd_get_data_type(dtd), dtd_get_notify(dtd), dtd_get_field(dtd), 7608c2ecf20Sopenharmony_ci dtd_get_1d(dtd), dtd_get_even_line_skip(dtd), 7618c2ecf20Sopenharmony_ci dtd_get_odd_line_skip(dtd), dtd_get_line_stride(dtd)); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (dir == DTD_DIR_IN) 7648c2ecf20Sopenharmony_ci pr_debug("word1: line_length = %d, xfer_height = %d\n", 7658c2ecf20Sopenharmony_ci dtd_get_line_length(dtd), dtd_get_xfer_height(dtd)); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci pr_debug("word2: start_addr = %x\n", dtd->start_addr); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci pr_debug("word3: pkt_type = %d, mode = %d, dir = %d, chan = %d, pri = %d, next_chan = %d\n", 7708c2ecf20Sopenharmony_ci dtd_get_pkt_type(dtd), 7718c2ecf20Sopenharmony_ci dtd_get_mode(dtd), dir, chan, dtd_get_priority(dtd), 7728c2ecf20Sopenharmony_ci dtd_get_next_chan(dtd)); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (dir == DTD_DIR_IN) 7758c2ecf20Sopenharmony_ci pr_debug("word4: frame_width = %d, frame_height = %d\n", 7768c2ecf20Sopenharmony_ci dtd_get_frame_width(dtd), dtd_get_frame_height(dtd)); 7778c2ecf20Sopenharmony_ci else 7788c2ecf20Sopenharmony_ci pr_debug("word4: desc_write_addr = 0x%08x, write_desc = %d, drp_data = %d, use_desc_reg = %d\n", 7798c2ecf20Sopenharmony_ci dtd_get_desc_write_addr(dtd), dtd_get_write_desc(dtd), 7808c2ecf20Sopenharmony_ci dtd_get_drop_data(dtd), dtd_get_use_desc(dtd)); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci if (dir == DTD_DIR_IN) 7838c2ecf20Sopenharmony_ci pr_debug("word5: hor_start = %d, ver_start = %d\n", 7848c2ecf20Sopenharmony_ci dtd_get_h_start(dtd), dtd_get_v_start(dtd)); 7858c2ecf20Sopenharmony_ci else 7868c2ecf20Sopenharmony_ci pr_debug("word5: max_width %d, max_height %d\n", 7878c2ecf20Sopenharmony_ci dtd_get_max_width(dtd), dtd_get_max_height(dtd)); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci pr_debug("word6: client specific attr0 = 0x%08x\n", dtd->client_attr0); 7908c2ecf20Sopenharmony_ci pr_debug("word7: client specific attr1 = 0x%08x\n", dtd->client_attr1); 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci/* 7948c2ecf20Sopenharmony_ci * append an outbound data transfer descriptor to the given descriptor list, 7958c2ecf20Sopenharmony_ci * this sets up a 'client to memory' VPDMA transfer for the given VPDMA channel 7968c2ecf20Sopenharmony_ci * 7978c2ecf20Sopenharmony_ci * @list: vpdma desc list to which we add this descriptor 7988c2ecf20Sopenharmony_ci * @width: width of the image in pixels in memory 7998c2ecf20Sopenharmony_ci * @c_rect: compose params of output image 8008c2ecf20Sopenharmony_ci * @fmt: vpdma data format of the buffer 8018c2ecf20Sopenharmony_ci * dma_addr: dma address as seen by VPDMA 8028c2ecf20Sopenharmony_ci * max_width: enum for maximum width of data transfer 8038c2ecf20Sopenharmony_ci * max_height: enum for maximum height of data transfer 8048c2ecf20Sopenharmony_ci * chan: VPDMA channel 8058c2ecf20Sopenharmony_ci * flags: VPDMA flags to configure some descriptor fields 8068c2ecf20Sopenharmony_ci */ 8078c2ecf20Sopenharmony_civoid vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, 8088c2ecf20Sopenharmony_ci int stride, const struct v4l2_rect *c_rect, 8098c2ecf20Sopenharmony_ci const struct vpdma_data_format *fmt, dma_addr_t dma_addr, 8108c2ecf20Sopenharmony_ci int max_w, int max_h, enum vpdma_channel chan, u32 flags) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci vpdma_rawchan_add_out_dtd(list, width, stride, c_rect, fmt, dma_addr, 8138c2ecf20Sopenharmony_ci max_w, max_h, chan_info[chan].num, flags); 8148c2ecf20Sopenharmony_ci} 8158c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_add_out_dtd); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_civoid vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width, 8188c2ecf20Sopenharmony_ci int stride, const struct v4l2_rect *c_rect, 8198c2ecf20Sopenharmony_ci const struct vpdma_data_format *fmt, dma_addr_t dma_addr, 8208c2ecf20Sopenharmony_ci int max_w, int max_h, int raw_vpdma_chan, u32 flags) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci int priority = 0; 8238c2ecf20Sopenharmony_ci int field = 0; 8248c2ecf20Sopenharmony_ci int notify = 1; 8258c2ecf20Sopenharmony_ci int channel, next_chan; 8268c2ecf20Sopenharmony_ci struct v4l2_rect rect = *c_rect; 8278c2ecf20Sopenharmony_ci int depth = fmt->depth; 8288c2ecf20Sopenharmony_ci struct vpdma_dtd *dtd; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci channel = next_chan = raw_vpdma_chan; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV && 8338c2ecf20Sopenharmony_ci (fmt->data_type == DATA_TYPE_C420 || 8348c2ecf20Sopenharmony_ci fmt->data_type == DATA_TYPE_CB420)) { 8358c2ecf20Sopenharmony_ci rect.height >>= 1; 8368c2ecf20Sopenharmony_ci rect.top >>= 1; 8378c2ecf20Sopenharmony_ci depth = 8; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci dma_addr += rect.top * stride + (rect.left * depth >> 3); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci dtd = list->next; 8438c2ecf20Sopenharmony_ci WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size)); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci dtd->type_ctl_stride = dtd_type_ctl_stride(fmt->data_type, 8468c2ecf20Sopenharmony_ci notify, 8478c2ecf20Sopenharmony_ci field, 8488c2ecf20Sopenharmony_ci !!(flags & VPDMA_DATA_FRAME_1D), 8498c2ecf20Sopenharmony_ci !!(flags & VPDMA_DATA_EVEN_LINE_SKIP), 8508c2ecf20Sopenharmony_ci !!(flags & VPDMA_DATA_ODD_LINE_SKIP), 8518c2ecf20Sopenharmony_ci stride); 8528c2ecf20Sopenharmony_ci dtd->w1 = 0; 8538c2ecf20Sopenharmony_ci dtd->start_addr = (u32) dma_addr; 8548c2ecf20Sopenharmony_ci dtd->pkt_ctl = dtd_pkt_ctl(!!(flags & VPDMA_DATA_MODE_TILED), 8558c2ecf20Sopenharmony_ci DTD_DIR_OUT, channel, priority, next_chan); 8568c2ecf20Sopenharmony_ci dtd->desc_write_addr = dtd_desc_write_addr(0, 0, 0, 0); 8578c2ecf20Sopenharmony_ci dtd->max_width_height = dtd_max_width_height(max_w, max_h); 8588c2ecf20Sopenharmony_ci dtd->client_attr0 = 0; 8598c2ecf20Sopenharmony_ci dtd->client_attr1 = 0; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci list->next = dtd + 1; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci dump_dtd(dtd); 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_rawchan_add_out_dtd); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci/* 8688c2ecf20Sopenharmony_ci * append an inbound data transfer descriptor to the given descriptor list, 8698c2ecf20Sopenharmony_ci * this sets up a 'memory to client' VPDMA transfer for the given VPDMA channel 8708c2ecf20Sopenharmony_ci * 8718c2ecf20Sopenharmony_ci * @list: vpdma desc list to which we add this descriptor 8728c2ecf20Sopenharmony_ci * @width: width of the image in pixels in memory(not the cropped width) 8738c2ecf20Sopenharmony_ci * @c_rect: crop params of input image 8748c2ecf20Sopenharmony_ci * @fmt: vpdma data format of the buffer 8758c2ecf20Sopenharmony_ci * dma_addr: dma address as seen by VPDMA 8768c2ecf20Sopenharmony_ci * chan: VPDMA channel 8778c2ecf20Sopenharmony_ci * field: top or bottom field info of the input image 8788c2ecf20Sopenharmony_ci * flags: VPDMA flags to configure some descriptor fields 8798c2ecf20Sopenharmony_ci * frame_width/height: the complete width/height of the image presented to the 8808c2ecf20Sopenharmony_ci * client (this makes sense when multiple channels are 8818c2ecf20Sopenharmony_ci * connected to the same client, forming a larger frame) 8828c2ecf20Sopenharmony_ci * start_h, start_v: position where the given channel starts providing pixel 8838c2ecf20Sopenharmony_ci * data to the client (makes sense when multiple channels 8848c2ecf20Sopenharmony_ci * contribute to the client) 8858c2ecf20Sopenharmony_ci */ 8868c2ecf20Sopenharmony_civoid vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, 8878c2ecf20Sopenharmony_ci int stride, const struct v4l2_rect *c_rect, 8888c2ecf20Sopenharmony_ci const struct vpdma_data_format *fmt, dma_addr_t dma_addr, 8898c2ecf20Sopenharmony_ci enum vpdma_channel chan, int field, u32 flags, int frame_width, 8908c2ecf20Sopenharmony_ci int frame_height, int start_h, int start_v) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci int priority = 0; 8938c2ecf20Sopenharmony_ci int notify = 1; 8948c2ecf20Sopenharmony_ci int depth = fmt->depth; 8958c2ecf20Sopenharmony_ci int channel, next_chan; 8968c2ecf20Sopenharmony_ci struct v4l2_rect rect = *c_rect; 8978c2ecf20Sopenharmony_ci struct vpdma_dtd *dtd; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci channel = next_chan = chan_info[chan].num; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV && 9028c2ecf20Sopenharmony_ci (fmt->data_type == DATA_TYPE_C420 || 9038c2ecf20Sopenharmony_ci fmt->data_type == DATA_TYPE_CB420)) { 9048c2ecf20Sopenharmony_ci rect.height >>= 1; 9058c2ecf20Sopenharmony_ci rect.top >>= 1; 9068c2ecf20Sopenharmony_ci depth = 8; 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci dma_addr += rect.top * stride + (rect.left * depth >> 3); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci dtd = list->next; 9128c2ecf20Sopenharmony_ci WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size)); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci dtd->type_ctl_stride = dtd_type_ctl_stride(fmt->data_type, 9158c2ecf20Sopenharmony_ci notify, 9168c2ecf20Sopenharmony_ci field, 9178c2ecf20Sopenharmony_ci !!(flags & VPDMA_DATA_FRAME_1D), 9188c2ecf20Sopenharmony_ci !!(flags & VPDMA_DATA_EVEN_LINE_SKIP), 9198c2ecf20Sopenharmony_ci !!(flags & VPDMA_DATA_ODD_LINE_SKIP), 9208c2ecf20Sopenharmony_ci stride); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci dtd->xfer_length_height = dtd_xfer_length_height(rect.width, 9238c2ecf20Sopenharmony_ci rect.height); 9248c2ecf20Sopenharmony_ci dtd->start_addr = (u32) dma_addr; 9258c2ecf20Sopenharmony_ci dtd->pkt_ctl = dtd_pkt_ctl(!!(flags & VPDMA_DATA_MODE_TILED), 9268c2ecf20Sopenharmony_ci DTD_DIR_IN, channel, priority, next_chan); 9278c2ecf20Sopenharmony_ci dtd->frame_width_height = dtd_frame_width_height(frame_width, 9288c2ecf20Sopenharmony_ci frame_height); 9298c2ecf20Sopenharmony_ci dtd->start_h_v = dtd_start_h_v(start_h, start_v); 9308c2ecf20Sopenharmony_ci dtd->client_attr0 = 0; 9318c2ecf20Sopenharmony_ci dtd->client_attr1 = 0; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci list->next = dtd + 1; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci dump_dtd(dtd); 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_add_in_dtd); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ciint vpdma_hwlist_alloc(struct vpdma_data *vpdma, void *priv) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci int i, list_num = -1; 9428c2ecf20Sopenharmony_ci unsigned long flags; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci spin_lock_irqsave(&vpdma->lock, flags); 9458c2ecf20Sopenharmony_ci for (i = 0; i < VPDMA_MAX_NUM_LIST && 9468c2ecf20Sopenharmony_ci vpdma->hwlist_used[i] == true; i++) 9478c2ecf20Sopenharmony_ci ; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if (i < VPDMA_MAX_NUM_LIST) { 9508c2ecf20Sopenharmony_ci list_num = i; 9518c2ecf20Sopenharmony_ci vpdma->hwlist_used[i] = true; 9528c2ecf20Sopenharmony_ci vpdma->hwlist_priv[i] = priv; 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vpdma->lock, flags); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci return list_num; 9578c2ecf20Sopenharmony_ci} 9588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_hwlist_alloc); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_civoid *vpdma_hwlist_get_priv(struct vpdma_data *vpdma, int list_num) 9618c2ecf20Sopenharmony_ci{ 9628c2ecf20Sopenharmony_ci if (!vpdma || list_num >= VPDMA_MAX_NUM_LIST) 9638c2ecf20Sopenharmony_ci return NULL; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci return vpdma->hwlist_priv[list_num]; 9668c2ecf20Sopenharmony_ci} 9678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_hwlist_get_priv); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_civoid *vpdma_hwlist_release(struct vpdma_data *vpdma, int list_num) 9708c2ecf20Sopenharmony_ci{ 9718c2ecf20Sopenharmony_ci void *priv; 9728c2ecf20Sopenharmony_ci unsigned long flags; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci spin_lock_irqsave(&vpdma->lock, flags); 9758c2ecf20Sopenharmony_ci vpdma->hwlist_used[list_num] = false; 9768c2ecf20Sopenharmony_ci priv = vpdma->hwlist_priv; 9778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vpdma->lock, flags); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci return priv; 9808c2ecf20Sopenharmony_ci} 9818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_hwlist_release); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci/* set or clear the mask for list complete interrupt */ 9848c2ecf20Sopenharmony_civoid vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int irq_num, 9858c2ecf20Sopenharmony_ci int list_num, bool enable) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci u32 reg_addr = VPDMA_INT_LIST0_MASK + VPDMA_INTX_OFFSET * irq_num; 9888c2ecf20Sopenharmony_ci u32 val; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci val = read_reg(vpdma, reg_addr); 9918c2ecf20Sopenharmony_ci if (enable) 9928c2ecf20Sopenharmony_ci val |= (1 << (list_num * 2)); 9938c2ecf20Sopenharmony_ci else 9948c2ecf20Sopenharmony_ci val &= ~(1 << (list_num * 2)); 9958c2ecf20Sopenharmony_ci write_reg(vpdma, reg_addr, val); 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_enable_list_complete_irq); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci/* get the LIST_STAT register */ 10008c2ecf20Sopenharmony_ciunsigned int vpdma_get_list_stat(struct vpdma_data *vpdma, int irq_num) 10018c2ecf20Sopenharmony_ci{ 10028c2ecf20Sopenharmony_ci u32 reg_addr = VPDMA_INT_LIST0_STAT + VPDMA_INTX_OFFSET * irq_num; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci return read_reg(vpdma, reg_addr); 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_get_list_stat); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci/* get the LIST_MASK register */ 10098c2ecf20Sopenharmony_ciunsigned int vpdma_get_list_mask(struct vpdma_data *vpdma, int irq_num) 10108c2ecf20Sopenharmony_ci{ 10118c2ecf20Sopenharmony_ci u32 reg_addr = VPDMA_INT_LIST0_MASK + VPDMA_INTX_OFFSET * irq_num; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci return read_reg(vpdma, reg_addr); 10148c2ecf20Sopenharmony_ci} 10158c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_get_list_mask); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci/* clear previously occurred list interrupts in the LIST_STAT register */ 10188c2ecf20Sopenharmony_civoid vpdma_clear_list_stat(struct vpdma_data *vpdma, int irq_num, 10198c2ecf20Sopenharmony_ci int list_num) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci u32 reg_addr = VPDMA_INT_LIST0_STAT + VPDMA_INTX_OFFSET * irq_num; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci write_reg(vpdma, reg_addr, 3 << (list_num * 2)); 10248c2ecf20Sopenharmony_ci} 10258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_clear_list_stat); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_civoid vpdma_set_bg_color(struct vpdma_data *vpdma, 10288c2ecf20Sopenharmony_ci struct vpdma_data_format *fmt, u32 color) 10298c2ecf20Sopenharmony_ci{ 10308c2ecf20Sopenharmony_ci if (fmt->type == VPDMA_DATA_FMT_TYPE_RGB) 10318c2ecf20Sopenharmony_ci write_reg(vpdma, VPDMA_BG_RGB, color); 10328c2ecf20Sopenharmony_ci else if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV) 10338c2ecf20Sopenharmony_ci write_reg(vpdma, VPDMA_BG_YUV, color); 10348c2ecf20Sopenharmony_ci} 10358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_set_bg_color); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci/* 10388c2ecf20Sopenharmony_ci * configures the output mode of the line buffer for the given client, the 10398c2ecf20Sopenharmony_ci * line buffer content can either be mirrored(each line repeated twice) or 10408c2ecf20Sopenharmony_ci * passed to the client as is 10418c2ecf20Sopenharmony_ci */ 10428c2ecf20Sopenharmony_civoid vpdma_set_line_mode(struct vpdma_data *vpdma, int line_mode, 10438c2ecf20Sopenharmony_ci enum vpdma_channel chan) 10448c2ecf20Sopenharmony_ci{ 10458c2ecf20Sopenharmony_ci int client_cstat = chan_info[chan].cstat_offset; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci write_field_reg(vpdma, client_cstat, line_mode, 10488c2ecf20Sopenharmony_ci VPDMA_CSTAT_LINE_MODE_MASK, VPDMA_CSTAT_LINE_MODE_SHIFT); 10498c2ecf20Sopenharmony_ci} 10508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_set_line_mode); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci/* 10538c2ecf20Sopenharmony_ci * configures the event which should trigger VPDMA transfer for the given 10548c2ecf20Sopenharmony_ci * client 10558c2ecf20Sopenharmony_ci */ 10568c2ecf20Sopenharmony_civoid vpdma_set_frame_start_event(struct vpdma_data *vpdma, 10578c2ecf20Sopenharmony_ci enum vpdma_frame_start_event fs_event, 10588c2ecf20Sopenharmony_ci enum vpdma_channel chan) 10598c2ecf20Sopenharmony_ci{ 10608c2ecf20Sopenharmony_ci int client_cstat = chan_info[chan].cstat_offset; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci write_field_reg(vpdma, client_cstat, fs_event, 10638c2ecf20Sopenharmony_ci VPDMA_CSTAT_FRAME_START_MASK, VPDMA_CSTAT_FRAME_START_SHIFT); 10648c2ecf20Sopenharmony_ci} 10658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_set_frame_start_event); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_cistatic void vpdma_firmware_cb(const struct firmware *f, void *context) 10688c2ecf20Sopenharmony_ci{ 10698c2ecf20Sopenharmony_ci struct vpdma_data *vpdma = context; 10708c2ecf20Sopenharmony_ci struct vpdma_buf fw_dma_buf; 10718c2ecf20Sopenharmony_ci int i, r; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci dev_dbg(&vpdma->pdev->dev, "firmware callback\n"); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci if (!f || !f->data) { 10768c2ecf20Sopenharmony_ci dev_err(&vpdma->pdev->dev, "couldn't get firmware\n"); 10778c2ecf20Sopenharmony_ci return; 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci /* already initialized */ 10818c2ecf20Sopenharmony_ci if (read_field_reg(vpdma, VPDMA_LIST_ATTR, VPDMA_LIST_RDY_MASK, 10828c2ecf20Sopenharmony_ci VPDMA_LIST_RDY_SHFT)) { 10838c2ecf20Sopenharmony_ci vpdma->cb(vpdma->pdev); 10848c2ecf20Sopenharmony_ci return; 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci r = vpdma_alloc_desc_buf(&fw_dma_buf, f->size); 10888c2ecf20Sopenharmony_ci if (r) { 10898c2ecf20Sopenharmony_ci dev_err(&vpdma->pdev->dev, 10908c2ecf20Sopenharmony_ci "failed to allocate dma buffer for firmware\n"); 10918c2ecf20Sopenharmony_ci goto rel_fw; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci memcpy(fw_dma_buf.addr, f->data, f->size); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci vpdma_map_desc_buf(vpdma, &fw_dma_buf); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci write_reg(vpdma, VPDMA_LIST_ADDR, (u32) fw_dma_buf.dma_addr); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci for (i = 0; i < 100; i++) { /* max 1 second */ 11018c2ecf20Sopenharmony_ci msleep_interruptible(10); 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci if (read_field_reg(vpdma, VPDMA_LIST_ATTR, VPDMA_LIST_RDY_MASK, 11048c2ecf20Sopenharmony_ci VPDMA_LIST_RDY_SHFT)) 11058c2ecf20Sopenharmony_ci break; 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci if (i == 100) { 11098c2ecf20Sopenharmony_ci dev_err(&vpdma->pdev->dev, "firmware upload failed\n"); 11108c2ecf20Sopenharmony_ci goto free_buf; 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci vpdma->cb(vpdma->pdev); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_cifree_buf: 11168c2ecf20Sopenharmony_ci vpdma_unmap_desc_buf(vpdma, &fw_dma_buf); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci vpdma_free_desc_buf(&fw_dma_buf); 11198c2ecf20Sopenharmony_cirel_fw: 11208c2ecf20Sopenharmony_ci release_firmware(f); 11218c2ecf20Sopenharmony_ci} 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_cistatic int vpdma_load_firmware(struct vpdma_data *vpdma) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci int r; 11268c2ecf20Sopenharmony_ci struct device *dev = &vpdma->pdev->dev; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci r = request_firmware_nowait(THIS_MODULE, 1, 11298c2ecf20Sopenharmony_ci (const char *) VPDMA_FIRMWARE, dev, GFP_KERNEL, vpdma, 11308c2ecf20Sopenharmony_ci vpdma_firmware_cb); 11318c2ecf20Sopenharmony_ci if (r) { 11328c2ecf20Sopenharmony_ci dev_err(dev, "firmware not available %s\n", VPDMA_FIRMWARE); 11338c2ecf20Sopenharmony_ci return r; 11348c2ecf20Sopenharmony_ci } else { 11358c2ecf20Sopenharmony_ci dev_info(dev, "loading firmware %s\n", VPDMA_FIRMWARE); 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci return 0; 11398c2ecf20Sopenharmony_ci} 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ciint vpdma_create(struct platform_device *pdev, struct vpdma_data *vpdma, 11428c2ecf20Sopenharmony_ci void (*cb)(struct platform_device *pdev)) 11438c2ecf20Sopenharmony_ci{ 11448c2ecf20Sopenharmony_ci struct resource *res; 11458c2ecf20Sopenharmony_ci int r; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "vpdma_create\n"); 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci vpdma->pdev = pdev; 11508c2ecf20Sopenharmony_ci vpdma->cb = cb; 11518c2ecf20Sopenharmony_ci spin_lock_init(&vpdma->lock); 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpdma"); 11548c2ecf20Sopenharmony_ci if (res == NULL) { 11558c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "missing platform resources data\n"); 11568c2ecf20Sopenharmony_ci return -ENODEV; 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci vpdma->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); 11608c2ecf20Sopenharmony_ci if (!vpdma->base) { 11618c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to ioremap\n"); 11628c2ecf20Sopenharmony_ci return -ENOMEM; 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci r = vpdma_load_firmware(vpdma); 11668c2ecf20Sopenharmony_ci if (r) { 11678c2ecf20Sopenharmony_ci pr_err("failed to load firmware %s\n", VPDMA_FIRMWARE); 11688c2ecf20Sopenharmony_ci return r; 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci return 0; 11728c2ecf20Sopenharmony_ci} 11738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(vpdma_create); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ciMODULE_AUTHOR("Texas Instruments Inc."); 11768c2ecf20Sopenharmony_ciMODULE_FIRMWARE(VPDMA_FIRMWARE); 11778c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1178