18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2019 NXP. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/delay.h> 78c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 88c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 98c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "dcss-dev.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define DCSS_CTXLD_CONTROL_STATUS 0x0 158c2ecf20Sopenharmony_ci#define CTXLD_ENABLE BIT(0) 168c2ecf20Sopenharmony_ci#define ARB_SEL BIT(1) 178c2ecf20Sopenharmony_ci#define RD_ERR_EN BIT(2) 188c2ecf20Sopenharmony_ci#define DB_COMP_EN BIT(3) 198c2ecf20Sopenharmony_ci#define SB_HP_COMP_EN BIT(4) 208c2ecf20Sopenharmony_ci#define SB_LP_COMP_EN BIT(5) 218c2ecf20Sopenharmony_ci#define DB_PEND_SB_REC_EN BIT(6) 228c2ecf20Sopenharmony_ci#define SB_PEND_DISP_ACTIVE_EN BIT(7) 238c2ecf20Sopenharmony_ci#define AHB_ERR_EN BIT(8) 248c2ecf20Sopenharmony_ci#define RD_ERR BIT(16) 258c2ecf20Sopenharmony_ci#define DB_COMP BIT(17) 268c2ecf20Sopenharmony_ci#define SB_HP_COMP BIT(18) 278c2ecf20Sopenharmony_ci#define SB_LP_COMP BIT(19) 288c2ecf20Sopenharmony_ci#define DB_PEND_SB_REC BIT(20) 298c2ecf20Sopenharmony_ci#define SB_PEND_DISP_ACTIVE BIT(21) 308c2ecf20Sopenharmony_ci#define AHB_ERR BIT(22) 318c2ecf20Sopenharmony_ci#define DCSS_CTXLD_DB_BASE_ADDR 0x10 328c2ecf20Sopenharmony_ci#define DCSS_CTXLD_DB_COUNT 0x14 338c2ecf20Sopenharmony_ci#define DCSS_CTXLD_SB_BASE_ADDR 0x18 348c2ecf20Sopenharmony_ci#define DCSS_CTXLD_SB_COUNT 0x1C 358c2ecf20Sopenharmony_ci#define SB_HP_COUNT_POS 0 368c2ecf20Sopenharmony_ci#define SB_HP_COUNT_MASK 0xffff 378c2ecf20Sopenharmony_ci#define SB_LP_COUNT_POS 16 388c2ecf20Sopenharmony_ci#define SB_LP_COUNT_MASK 0xffff0000 398c2ecf20Sopenharmony_ci#define DCSS_AHB_ERR_ADDR 0x20 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define CTXLD_IRQ_COMPLETION (DB_COMP | SB_HP_COMP | SB_LP_COMP) 428c2ecf20Sopenharmony_ci#define CTXLD_IRQ_ERROR (RD_ERR | DB_PEND_SB_REC | AHB_ERR) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* The following sizes are in context loader entries, 8 bytes each. */ 458c2ecf20Sopenharmony_ci#define CTXLD_DB_CTX_ENTRIES 1024 /* max 65536 */ 468c2ecf20Sopenharmony_ci#define CTXLD_SB_LP_CTX_ENTRIES 10240 /* max 65536 */ 478c2ecf20Sopenharmony_ci#define CTXLD_SB_HP_CTX_ENTRIES 20000 /* max 65536 */ 488c2ecf20Sopenharmony_ci#define CTXLD_SB_CTX_ENTRIES (CTXLD_SB_LP_CTX_ENTRIES + \ 498c2ecf20Sopenharmony_ci CTXLD_SB_HP_CTX_ENTRIES) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* Sizes, in entries, of the DB, SB_HP and SB_LP context regions. */ 528c2ecf20Sopenharmony_cistatic u16 dcss_ctxld_ctx_size[3] = { 538c2ecf20Sopenharmony_ci CTXLD_DB_CTX_ENTRIES, 548c2ecf20Sopenharmony_ci CTXLD_SB_HP_CTX_ENTRIES, 558c2ecf20Sopenharmony_ci CTXLD_SB_LP_CTX_ENTRIES 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* this represents an entry in the context loader map */ 598c2ecf20Sopenharmony_cistruct dcss_ctxld_item { 608c2ecf20Sopenharmony_ci u32 val; 618c2ecf20Sopenharmony_ci u32 ofs; 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define CTX_ITEM_SIZE sizeof(struct dcss_ctxld_item) 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistruct dcss_ctxld { 678c2ecf20Sopenharmony_ci struct device *dev; 688c2ecf20Sopenharmony_ci void __iomem *ctxld_reg; 698c2ecf20Sopenharmony_ci int irq; 708c2ecf20Sopenharmony_ci bool irq_en; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci struct dcss_ctxld_item *db[2]; 738c2ecf20Sopenharmony_ci struct dcss_ctxld_item *sb_hp[2]; 748c2ecf20Sopenharmony_ci struct dcss_ctxld_item *sb_lp[2]; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci dma_addr_t db_paddr[2]; 778c2ecf20Sopenharmony_ci dma_addr_t sb_paddr[2]; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci u16 ctx_size[2][3]; /* holds the sizes of DB, SB_HP and SB_LP ctx */ 808c2ecf20Sopenharmony_ci u8 current_ctx; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci bool in_use; 838c2ecf20Sopenharmony_ci bool armed; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci spinlock_t lock; /* protects concurent access to private data */ 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic irqreturn_t dcss_ctxld_irq_handler(int irq, void *data) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct dcss_ctxld *ctxld = data; 918c2ecf20Sopenharmony_ci struct dcss_dev *dcss = dcss_drv_dev_to_dcss(ctxld->dev); 928c2ecf20Sopenharmony_ci u32 irq_status; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci irq_status = dcss_readl(ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (irq_status & CTXLD_IRQ_COMPLETION && 978c2ecf20Sopenharmony_ci !(irq_status & CTXLD_ENABLE) && ctxld->in_use) { 988c2ecf20Sopenharmony_ci ctxld->in_use = false; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (dcss && dcss->disable_callback) 1018c2ecf20Sopenharmony_ci dcss->disable_callback(dcss); 1028c2ecf20Sopenharmony_ci } else if (irq_status & CTXLD_IRQ_ERROR) { 1038c2ecf20Sopenharmony_ci /* 1048c2ecf20Sopenharmony_ci * Except for throwing an error message and clearing the status 1058c2ecf20Sopenharmony_ci * register, there's not much we can do here. 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci dev_err(ctxld->dev, "ctxld: error encountered: %08x\n", 1088c2ecf20Sopenharmony_ci irq_status); 1098c2ecf20Sopenharmony_ci dev_err(ctxld->dev, "ctxld: db=%d, sb_hp=%d, sb_lp=%d\n", 1108c2ecf20Sopenharmony_ci ctxld->ctx_size[ctxld->current_ctx ^ 1][CTX_DB], 1118c2ecf20Sopenharmony_ci ctxld->ctx_size[ctxld->current_ctx ^ 1][CTX_SB_HP], 1128c2ecf20Sopenharmony_ci ctxld->ctx_size[ctxld->current_ctx ^ 1][CTX_SB_LP]); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci dcss_clr(irq_status & (CTXLD_IRQ_ERROR | CTXLD_IRQ_COMPLETION), 1168c2ecf20Sopenharmony_ci ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic int dcss_ctxld_irq_config(struct dcss_ctxld *ctxld, 1228c2ecf20Sopenharmony_ci struct platform_device *pdev) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci int ret; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci ctxld->irq = platform_get_irq_byname(pdev, "ctxld"); 1278c2ecf20Sopenharmony_ci if (ctxld->irq < 0) 1288c2ecf20Sopenharmony_ci return ctxld->irq; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci ret = request_irq(ctxld->irq, dcss_ctxld_irq_handler, 1318c2ecf20Sopenharmony_ci 0, "dcss_ctxld", ctxld); 1328c2ecf20Sopenharmony_ci if (ret) { 1338c2ecf20Sopenharmony_ci dev_err(ctxld->dev, "ctxld: irq request failed.\n"); 1348c2ecf20Sopenharmony_ci return ret; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci ctxld->irq_en = true; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic void dcss_ctxld_hw_cfg(struct dcss_ctxld *ctxld) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci dcss_writel(RD_ERR_EN | SB_HP_COMP_EN | 1458c2ecf20Sopenharmony_ci DB_PEND_SB_REC_EN | AHB_ERR_EN | RD_ERR | AHB_ERR, 1468c2ecf20Sopenharmony_ci ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS); 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic void dcss_ctxld_free_ctx(struct dcss_ctxld *ctxld) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct dcss_ctxld_item *ctx; 1528c2ecf20Sopenharmony_ci int i; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 1558c2ecf20Sopenharmony_ci if (ctxld->db[i]) { 1568c2ecf20Sopenharmony_ci dma_free_coherent(ctxld->dev, 1578c2ecf20Sopenharmony_ci CTXLD_DB_CTX_ENTRIES * sizeof(*ctx), 1588c2ecf20Sopenharmony_ci ctxld->db[i], ctxld->db_paddr[i]); 1598c2ecf20Sopenharmony_ci ctxld->db[i] = NULL; 1608c2ecf20Sopenharmony_ci ctxld->db_paddr[i] = 0; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (ctxld->sb_hp[i]) { 1648c2ecf20Sopenharmony_ci dma_free_coherent(ctxld->dev, 1658c2ecf20Sopenharmony_ci CTXLD_SB_CTX_ENTRIES * sizeof(*ctx), 1668c2ecf20Sopenharmony_ci ctxld->sb_hp[i], ctxld->sb_paddr[i]); 1678c2ecf20Sopenharmony_ci ctxld->sb_hp[i] = NULL; 1688c2ecf20Sopenharmony_ci ctxld->sb_paddr[i] = 0; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic int dcss_ctxld_alloc_ctx(struct dcss_ctxld *ctxld) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct dcss_ctxld_item *ctx; 1768c2ecf20Sopenharmony_ci int i; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 1798c2ecf20Sopenharmony_ci ctx = dma_alloc_coherent(ctxld->dev, 1808c2ecf20Sopenharmony_ci CTXLD_DB_CTX_ENTRIES * sizeof(*ctx), 1818c2ecf20Sopenharmony_ci &ctxld->db_paddr[i], GFP_KERNEL); 1828c2ecf20Sopenharmony_ci if (!ctx) 1838c2ecf20Sopenharmony_ci return -ENOMEM; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci ctxld->db[i] = ctx; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci ctx = dma_alloc_coherent(ctxld->dev, 1888c2ecf20Sopenharmony_ci CTXLD_SB_CTX_ENTRIES * sizeof(*ctx), 1898c2ecf20Sopenharmony_ci &ctxld->sb_paddr[i], GFP_KERNEL); 1908c2ecf20Sopenharmony_ci if (!ctx) 1918c2ecf20Sopenharmony_ci return -ENOMEM; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci ctxld->sb_hp[i] = ctx; 1948c2ecf20Sopenharmony_ci ctxld->sb_lp[i] = ctx + CTXLD_SB_HP_CTX_ENTRIES; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return 0; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ciint dcss_ctxld_init(struct dcss_dev *dcss, unsigned long ctxld_base) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct dcss_ctxld *ctxld; 2038c2ecf20Sopenharmony_ci int ret; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci ctxld = kzalloc(sizeof(*ctxld), GFP_KERNEL); 2068c2ecf20Sopenharmony_ci if (!ctxld) 2078c2ecf20Sopenharmony_ci return -ENOMEM; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci dcss->ctxld = ctxld; 2108c2ecf20Sopenharmony_ci ctxld->dev = dcss->dev; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci spin_lock_init(&ctxld->lock); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci ret = dcss_ctxld_alloc_ctx(ctxld); 2158c2ecf20Sopenharmony_ci if (ret) { 2168c2ecf20Sopenharmony_ci dev_err(dcss->dev, "ctxld: cannot allocate context memory.\n"); 2178c2ecf20Sopenharmony_ci goto err; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci ctxld->ctxld_reg = ioremap(ctxld_base, SZ_4K); 2218c2ecf20Sopenharmony_ci if (!ctxld->ctxld_reg) { 2228c2ecf20Sopenharmony_ci dev_err(dcss->dev, "ctxld: unable to remap ctxld base\n"); 2238c2ecf20Sopenharmony_ci ret = -ENOMEM; 2248c2ecf20Sopenharmony_ci goto err; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci ret = dcss_ctxld_irq_config(ctxld, to_platform_device(dcss->dev)); 2288c2ecf20Sopenharmony_ci if (ret) 2298c2ecf20Sopenharmony_ci goto err_irq; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci dcss_ctxld_hw_cfg(ctxld); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return 0; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cierr_irq: 2368c2ecf20Sopenharmony_ci iounmap(ctxld->ctxld_reg); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cierr: 2398c2ecf20Sopenharmony_ci dcss_ctxld_free_ctx(ctxld); 2408c2ecf20Sopenharmony_ci kfree(ctxld); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return ret; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_civoid dcss_ctxld_exit(struct dcss_ctxld *ctxld) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci free_irq(ctxld->irq, ctxld); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (ctxld->ctxld_reg) 2508c2ecf20Sopenharmony_ci iounmap(ctxld->ctxld_reg); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci dcss_ctxld_free_ctx(ctxld); 2538c2ecf20Sopenharmony_ci kfree(ctxld); 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic int dcss_ctxld_enable_locked(struct dcss_ctxld *ctxld) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci int curr_ctx = ctxld->current_ctx; 2598c2ecf20Sopenharmony_ci u32 db_base, sb_base, sb_count; 2608c2ecf20Sopenharmony_ci u32 sb_hp_cnt, sb_lp_cnt, db_cnt; 2618c2ecf20Sopenharmony_ci struct dcss_dev *dcss = dcss_drv_dev_to_dcss(ctxld->dev); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (!dcss) 2648c2ecf20Sopenharmony_ci return 0; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci dcss_dpr_write_sysctrl(dcss->dpr); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci dcss_scaler_write_sclctrl(dcss->scaler); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci sb_hp_cnt = ctxld->ctx_size[curr_ctx][CTX_SB_HP]; 2718c2ecf20Sopenharmony_ci sb_lp_cnt = ctxld->ctx_size[curr_ctx][CTX_SB_LP]; 2728c2ecf20Sopenharmony_ci db_cnt = ctxld->ctx_size[curr_ctx][CTX_DB]; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* make sure SB_LP context area comes after SB_HP */ 2758c2ecf20Sopenharmony_ci if (sb_lp_cnt && 2768c2ecf20Sopenharmony_ci ctxld->sb_lp[curr_ctx] != ctxld->sb_hp[curr_ctx] + sb_hp_cnt) { 2778c2ecf20Sopenharmony_ci struct dcss_ctxld_item *sb_lp_adjusted; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci sb_lp_adjusted = ctxld->sb_hp[curr_ctx] + sb_hp_cnt; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci memcpy(sb_lp_adjusted, ctxld->sb_lp[curr_ctx], 2828c2ecf20Sopenharmony_ci sb_lp_cnt * CTX_ITEM_SIZE); 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci db_base = db_cnt ? ctxld->db_paddr[curr_ctx] : 0; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci dcss_writel(db_base, ctxld->ctxld_reg + DCSS_CTXLD_DB_BASE_ADDR); 2888c2ecf20Sopenharmony_ci dcss_writel(db_cnt, ctxld->ctxld_reg + DCSS_CTXLD_DB_COUNT); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (sb_hp_cnt) 2918c2ecf20Sopenharmony_ci sb_count = ((sb_hp_cnt << SB_HP_COUNT_POS) & SB_HP_COUNT_MASK) | 2928c2ecf20Sopenharmony_ci ((sb_lp_cnt << SB_LP_COUNT_POS) & SB_LP_COUNT_MASK); 2938c2ecf20Sopenharmony_ci else 2948c2ecf20Sopenharmony_ci sb_count = (sb_lp_cnt << SB_HP_COUNT_POS) & SB_HP_COUNT_MASK; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci sb_base = sb_count ? ctxld->sb_paddr[curr_ctx] : 0; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci dcss_writel(sb_base, ctxld->ctxld_reg + DCSS_CTXLD_SB_BASE_ADDR); 2998c2ecf20Sopenharmony_ci dcss_writel(sb_count, ctxld->ctxld_reg + DCSS_CTXLD_SB_COUNT); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* enable the context loader */ 3028c2ecf20Sopenharmony_ci dcss_set(CTXLD_ENABLE, ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci ctxld->in_use = true; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* 3078c2ecf20Sopenharmony_ci * Toggle the current context to the alternate one so that any updates 3088c2ecf20Sopenharmony_ci * in the modules' settings take place there. 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_ci ctxld->current_ctx ^= 1; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci ctxld->ctx_size[ctxld->current_ctx][CTX_DB] = 0; 3138c2ecf20Sopenharmony_ci ctxld->ctx_size[ctxld->current_ctx][CTX_SB_HP] = 0; 3148c2ecf20Sopenharmony_ci ctxld->ctx_size[ctxld->current_ctx][CTX_SB_LP] = 0; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci return 0; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ciint dcss_ctxld_enable(struct dcss_ctxld *ctxld) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci spin_lock_irq(&ctxld->lock); 3228c2ecf20Sopenharmony_ci ctxld->armed = true; 3238c2ecf20Sopenharmony_ci spin_unlock_irq(&ctxld->lock); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci return 0; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_civoid dcss_ctxld_kick(struct dcss_ctxld *ctxld) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci unsigned long flags; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci spin_lock_irqsave(&ctxld->lock, flags); 3338c2ecf20Sopenharmony_ci if (ctxld->armed && !ctxld->in_use) { 3348c2ecf20Sopenharmony_ci ctxld->armed = false; 3358c2ecf20Sopenharmony_ci dcss_ctxld_enable_locked(ctxld); 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ctxld->lock, flags); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_civoid dcss_ctxld_write_irqsafe(struct dcss_ctxld *ctxld, u32 ctx_id, u32 val, 3418c2ecf20Sopenharmony_ci u32 reg_ofs) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci int curr_ctx = ctxld->current_ctx; 3448c2ecf20Sopenharmony_ci struct dcss_ctxld_item *ctx[] = { 3458c2ecf20Sopenharmony_ci [CTX_DB] = ctxld->db[curr_ctx], 3468c2ecf20Sopenharmony_ci [CTX_SB_HP] = ctxld->sb_hp[curr_ctx], 3478c2ecf20Sopenharmony_ci [CTX_SB_LP] = ctxld->sb_lp[curr_ctx] 3488c2ecf20Sopenharmony_ci }; 3498c2ecf20Sopenharmony_ci int item_idx = ctxld->ctx_size[curr_ctx][ctx_id]; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (item_idx + 1 > dcss_ctxld_ctx_size[ctx_id]) { 3528c2ecf20Sopenharmony_ci WARN_ON(1); 3538c2ecf20Sopenharmony_ci return; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci ctx[ctx_id][item_idx].val = val; 3578c2ecf20Sopenharmony_ci ctx[ctx_id][item_idx].ofs = reg_ofs; 3588c2ecf20Sopenharmony_ci ctxld->ctx_size[curr_ctx][ctx_id] += 1; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_civoid dcss_ctxld_write(struct dcss_ctxld *ctxld, u32 ctx_id, 3628c2ecf20Sopenharmony_ci u32 val, u32 reg_ofs) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci spin_lock_irq(&ctxld->lock); 3658c2ecf20Sopenharmony_ci dcss_ctxld_write_irqsafe(ctxld, ctx_id, val, reg_ofs); 3668c2ecf20Sopenharmony_ci spin_unlock_irq(&ctxld->lock); 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cibool dcss_ctxld_is_flushed(struct dcss_ctxld *ctxld) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci return ctxld->ctx_size[ctxld->current_ctx][CTX_DB] == 0 && 3728c2ecf20Sopenharmony_ci ctxld->ctx_size[ctxld->current_ctx][CTX_SB_HP] == 0 && 3738c2ecf20Sopenharmony_ci ctxld->ctx_size[ctxld->current_ctx][CTX_SB_LP] == 0; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ciint dcss_ctxld_resume(struct dcss_ctxld *ctxld) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci dcss_ctxld_hw_cfg(ctxld); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (!ctxld->irq_en) { 3818c2ecf20Sopenharmony_ci enable_irq(ctxld->irq); 3828c2ecf20Sopenharmony_ci ctxld->irq_en = true; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ciint dcss_ctxld_suspend(struct dcss_ctxld *ctxld) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci int ret = 0; 3918c2ecf20Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(500); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (!dcss_ctxld_is_flushed(ctxld)) { 3948c2ecf20Sopenharmony_ci dcss_ctxld_kick(ctxld); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci while (!time_after(jiffies, timeout) && ctxld->in_use) 3978c2ecf20Sopenharmony_ci msleep(20); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (time_after(jiffies, timeout)) 4008c2ecf20Sopenharmony_ci return -ETIMEDOUT; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci spin_lock_irq(&ctxld->lock); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (ctxld->irq_en) { 4068c2ecf20Sopenharmony_ci disable_irq_nosync(ctxld->irq); 4078c2ecf20Sopenharmony_ci ctxld->irq_en = false; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci /* reset context region and sizes */ 4118c2ecf20Sopenharmony_ci ctxld->current_ctx = 0; 4128c2ecf20Sopenharmony_ci ctxld->ctx_size[0][CTX_DB] = 0; 4138c2ecf20Sopenharmony_ci ctxld->ctx_size[0][CTX_SB_HP] = 0; 4148c2ecf20Sopenharmony_ci ctxld->ctx_size[0][CTX_SB_LP] = 0; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci spin_unlock_irq(&ctxld->lock); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci return ret; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_civoid dcss_ctxld_assert_locked(struct dcss_ctxld *ctxld) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci lockdep_assert_held(&ctxld->lock); 4248c2ecf20Sopenharmony_ci} 425