1ab29a247SBingbu Cao // SPDX-License-Identifier: GPL-2.0-only 2ab29a247SBingbu Cao /* 3ab29a247SBingbu Cao * Copyright (C) 2013--2024 Intel Corporation 4ab29a247SBingbu Cao */ 5ab29a247SBingbu Cao 6ab29a247SBingbu Cao #include <linux/bitfield.h> 7ab29a247SBingbu Cao #include <linux/bits.h> 8ab29a247SBingbu Cao #include <linux/completion.h> 9ab29a247SBingbu Cao #include <linux/delay.h> 10ab29a247SBingbu Cao #include <linux/device.h> 11ab29a247SBingbu Cao #include <linux/dma-mapping.h> 12ab29a247SBingbu Cao #include <linux/firmware.h> 13ab29a247SBingbu Cao #include <linux/interrupt.h> 14ab29a247SBingbu Cao #include <linux/iopoll.h> 15ab29a247SBingbu Cao #include <linux/math64.h> 16ab29a247SBingbu Cao #include <linux/mm.h> 17ab29a247SBingbu Cao #include <linux/mutex.h> 18ab29a247SBingbu Cao #include <linux/pci.h> 19ab29a247SBingbu Cao #include <linux/pfn.h> 20ab29a247SBingbu Cao #include <linux/pm_runtime.h> 21ab29a247SBingbu Cao #include <linux/scatterlist.h> 22ab29a247SBingbu Cao #include <linux/slab.h> 23ab29a247SBingbu Cao #include <linux/time64.h> 24ab29a247SBingbu Cao 25ab29a247SBingbu Cao #include "ipu6.h" 26ab29a247SBingbu Cao #include "ipu6-bus.h" 27ab29a247SBingbu Cao #include "ipu6-buttress.h" 28ab29a247SBingbu Cao #include "ipu6-platform-buttress-regs.h" 29ab29a247SBingbu Cao 30ab29a247SBingbu Cao #define BOOTLOADER_STATUS_OFFSET 0x15c 31ab29a247SBingbu Cao 32ab29a247SBingbu Cao #define BOOTLOADER_MAGIC_KEY 0xb00710ad 33ab29a247SBingbu Cao 34ab29a247SBingbu Cao #define ENTRY BUTTRESS_IU2CSECSR_IPC_PEER_COMP_ACTIONS_RST_PHASE1 35ab29a247SBingbu Cao #define EXIT BUTTRESS_IU2CSECSR_IPC_PEER_COMP_ACTIONS_RST_PHASE2 36ab29a247SBingbu Cao #define QUERY BUTTRESS_IU2CSECSR_IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE 37ab29a247SBingbu Cao 38ab29a247SBingbu Cao #define BUTTRESS_TSC_SYNC_RESET_TRIAL_MAX 10 39ab29a247SBingbu Cao 40ab29a247SBingbu Cao #define BUTTRESS_POWER_TIMEOUT_US (200 * USEC_PER_MSEC) 41ab29a247SBingbu Cao 42ab29a247SBingbu Cao #define BUTTRESS_CSE_BOOTLOAD_TIMEOUT_US (5 * USEC_PER_SEC) 43ab29a247SBingbu Cao #define BUTTRESS_CSE_AUTHENTICATE_TIMEOUT_US (10 * USEC_PER_SEC) 44ab29a247SBingbu Cao #define BUTTRESS_CSE_FWRESET_TIMEOUT_US (100 * USEC_PER_MSEC) 45ab29a247SBingbu Cao 46ab29a247SBingbu Cao #define BUTTRESS_IPC_TX_TIMEOUT_MS MSEC_PER_SEC 47ab29a247SBingbu Cao #define BUTTRESS_IPC_RX_TIMEOUT_MS MSEC_PER_SEC 48ab29a247SBingbu Cao #define BUTTRESS_IPC_VALIDITY_TIMEOUT_US (1 * USEC_PER_SEC) 49ab29a247SBingbu Cao #define BUTTRESS_TSC_SYNC_TIMEOUT_US (5 * USEC_PER_MSEC) 50ab29a247SBingbu Cao 51ab29a247SBingbu Cao #define BUTTRESS_IPC_RESET_RETRY 2000 52ab29a247SBingbu Cao #define BUTTRESS_CSE_IPC_RESET_RETRY 4 53ab29a247SBingbu Cao #define BUTTRESS_IPC_CMD_SEND_RETRY 1 54ab29a247SBingbu Cao 55ab29a247SBingbu Cao #define BUTTRESS_MAX_CONSECUTIVE_IRQS 100 56ab29a247SBingbu Cao 57ab29a247SBingbu Cao static const u32 ipu6_adev_irq_mask[2] = { 58ab29a247SBingbu Cao BUTTRESS_ISR_IS_IRQ, 59ab29a247SBingbu Cao BUTTRESS_ISR_PS_IRQ 60ab29a247SBingbu Cao }; 61ab29a247SBingbu Cao 62ab29a247SBingbu Cao int ipu6_buttress_ipc_reset(struct ipu6_device *isp, 63ab29a247SBingbu Cao struct ipu6_buttress_ipc *ipc) 64ab29a247SBingbu Cao { 65ab29a247SBingbu Cao unsigned int retries = BUTTRESS_IPC_RESET_RETRY; 66ab29a247SBingbu Cao struct ipu6_buttress *b = &isp->buttress; 67ab29a247SBingbu Cao u32 val = 0, csr_in_clr; 68ab29a247SBingbu Cao 69ab29a247SBingbu Cao if (!isp->secure_mode) { 70ab29a247SBingbu Cao dev_dbg(&isp->pdev->dev, "Skip IPC reset for non-secure mode"); 71ab29a247SBingbu Cao return 0; 72ab29a247SBingbu Cao } 73ab29a247SBingbu Cao 74ab29a247SBingbu Cao mutex_lock(&b->ipc_mutex); 75ab29a247SBingbu Cao 76ab29a247SBingbu Cao /* Clear-by-1 CSR (all bits), corresponding internal states. */ 77ab29a247SBingbu Cao val = readl(isp->base + ipc->csr_in); 78ab29a247SBingbu Cao writel(val, isp->base + ipc->csr_in); 79ab29a247SBingbu Cao 80ab29a247SBingbu Cao /* Set peer CSR bit IPC_PEER_COMP_ACTIONS_RST_PHASE1 */ 81ab29a247SBingbu Cao writel(ENTRY, isp->base + ipc->csr_out); 82ab29a247SBingbu Cao /* 83ab29a247SBingbu Cao * Clear-by-1 all CSR bits EXCEPT following 84ab29a247SBingbu Cao * bits: 85ab29a247SBingbu Cao * A. IPC_PEER_COMP_ACTIONS_RST_PHASE1. 86ab29a247SBingbu Cao * B. IPC_PEER_COMP_ACTIONS_RST_PHASE2. 87ab29a247SBingbu Cao * C. Possibly custom bits, depending on 88ab29a247SBingbu Cao * their role. 89ab29a247SBingbu Cao */ 90ab29a247SBingbu Cao csr_in_clr = BUTTRESS_IU2CSECSR_IPC_PEER_DEASSERTED_REG_VALID_REQ | 91ab29a247SBingbu Cao BUTTRESS_IU2CSECSR_IPC_PEER_ACKED_REG_VALID | 92ab29a247SBingbu Cao BUTTRESS_IU2CSECSR_IPC_PEER_ASSERTED_REG_VALID_REQ | QUERY; 93ab29a247SBingbu Cao 94ab29a247SBingbu Cao do { 95ab29a247SBingbu Cao usleep_range(400, 500); 96ab29a247SBingbu Cao val = readl(isp->base + ipc->csr_in); 97ab29a247SBingbu Cao switch (val) { 98ab29a247SBingbu Cao case ENTRY | EXIT: 99ab29a247SBingbu Cao case ENTRY | EXIT | QUERY: 100ab29a247SBingbu Cao /* 101ab29a247SBingbu Cao * 1) Clear-by-1 CSR bits 102ab29a247SBingbu Cao * (IPC_PEER_COMP_ACTIONS_RST_PHASE1, 103ab29a247SBingbu Cao * IPC_PEER_COMP_ACTIONS_RST_PHASE2). 104ab29a247SBingbu Cao * 2) Set peer CSR bit 105ab29a247SBingbu Cao * IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE. 106ab29a247SBingbu Cao */ 107ab29a247SBingbu Cao writel(ENTRY | EXIT, isp->base + ipc->csr_in); 108ab29a247SBingbu Cao writel(QUERY, isp->base + ipc->csr_out); 109ab29a247SBingbu Cao break; 110ab29a247SBingbu Cao case ENTRY: 111ab29a247SBingbu Cao case ENTRY | QUERY: 112ab29a247SBingbu Cao /* 113ab29a247SBingbu Cao * 1) Clear-by-1 CSR bits 114ab29a247SBingbu Cao * (IPC_PEER_COMP_ACTIONS_RST_PHASE1, 115ab29a247SBingbu Cao * IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE). 116ab29a247SBingbu Cao * 2) Set peer CSR bit 117ab29a247SBingbu Cao * IPC_PEER_COMP_ACTIONS_RST_PHASE1. 118ab29a247SBingbu Cao */ 119ab29a247SBingbu Cao writel(ENTRY | QUERY, isp->base + ipc->csr_in); 120ab29a247SBingbu Cao writel(ENTRY, isp->base + ipc->csr_out); 121ab29a247SBingbu Cao break; 122ab29a247SBingbu Cao case EXIT: 123ab29a247SBingbu Cao case EXIT | QUERY: 124ab29a247SBingbu Cao /* 125ab29a247SBingbu Cao * Clear-by-1 CSR bit 126ab29a247SBingbu Cao * IPC_PEER_COMP_ACTIONS_RST_PHASE2. 127ab29a247SBingbu Cao * 1) Clear incoming doorbell. 128ab29a247SBingbu Cao * 2) Clear-by-1 all CSR bits EXCEPT following 129ab29a247SBingbu Cao * bits: 130ab29a247SBingbu Cao * A. IPC_PEER_COMP_ACTIONS_RST_PHASE1. 131ab29a247SBingbu Cao * B. IPC_PEER_COMP_ACTIONS_RST_PHASE2. 132ab29a247SBingbu Cao * C. Possibly custom bits, depending on 133ab29a247SBingbu Cao * their role. 134ab29a247SBingbu Cao * 3) Set peer CSR bit 135ab29a247SBingbu Cao * IPC_PEER_COMP_ACTIONS_RST_PHASE2. 136ab29a247SBingbu Cao */ 137ab29a247SBingbu Cao writel(EXIT, isp->base + ipc->csr_in); 138ab29a247SBingbu Cao writel(0, isp->base + ipc->db0_in); 139ab29a247SBingbu Cao writel(csr_in_clr, isp->base + ipc->csr_in); 140ab29a247SBingbu Cao writel(EXIT, isp->base + ipc->csr_out); 141ab29a247SBingbu Cao 142ab29a247SBingbu Cao /* 143ab29a247SBingbu Cao * Read csr_in again to make sure if RST_PHASE2 is done. 144ab29a247SBingbu Cao * If csr_in is QUERY, it should be handled again. 145ab29a247SBingbu Cao */ 146ab29a247SBingbu Cao usleep_range(200, 300); 147ab29a247SBingbu Cao val = readl(isp->base + ipc->csr_in); 148ab29a247SBingbu Cao if (val & QUERY) { 149ab29a247SBingbu Cao dev_dbg(&isp->pdev->dev, 150ab29a247SBingbu Cao "RST_PHASE2 retry csr_in = %x\n", val); 151ab29a247SBingbu Cao break; 152ab29a247SBingbu Cao } 153ab29a247SBingbu Cao mutex_unlock(&b->ipc_mutex); 154ab29a247SBingbu Cao return 0; 155ab29a247SBingbu Cao case QUERY: 156ab29a247SBingbu Cao /* 157ab29a247SBingbu Cao * 1) Clear-by-1 CSR bit 158ab29a247SBingbu Cao * IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE. 159ab29a247SBingbu Cao * 2) Set peer CSR bit 160ab29a247SBingbu Cao * IPC_PEER_COMP_ACTIONS_RST_PHASE1 161ab29a247SBingbu Cao */ 162ab29a247SBingbu Cao writel(QUERY, isp->base + ipc->csr_in); 163ab29a247SBingbu Cao writel(ENTRY, isp->base + ipc->csr_out); 164ab29a247SBingbu Cao break; 165ab29a247SBingbu Cao default: 166ab29a247SBingbu Cao dev_warn_ratelimited(&isp->pdev->dev, 167ab29a247SBingbu Cao "Unexpected CSR 0x%x\n", val); 168ab29a247SBingbu Cao break; 169ab29a247SBingbu Cao } 170ab29a247SBingbu Cao } while (retries--); 171ab29a247SBingbu Cao 172ab29a247SBingbu Cao mutex_unlock(&b->ipc_mutex); 173ab29a247SBingbu Cao dev_err(&isp->pdev->dev, "Timed out while waiting for CSE\n"); 174ab29a247SBingbu Cao 175ab29a247SBingbu Cao return -ETIMEDOUT; 176ab29a247SBingbu Cao } 177ab29a247SBingbu Cao 178ab29a247SBingbu Cao static void ipu6_buttress_ipc_validity_close(struct ipu6_device *isp, 179ab29a247SBingbu Cao struct ipu6_buttress_ipc *ipc) 180ab29a247SBingbu Cao { 181ab29a247SBingbu Cao writel(BUTTRESS_IU2CSECSR_IPC_PEER_DEASSERTED_REG_VALID_REQ, 182ab29a247SBingbu Cao isp->base + ipc->csr_out); 183ab29a247SBingbu Cao } 184ab29a247SBingbu Cao 185ab29a247SBingbu Cao static int 186ab29a247SBingbu Cao ipu6_buttress_ipc_validity_open(struct ipu6_device *isp, 187ab29a247SBingbu Cao struct ipu6_buttress_ipc *ipc) 188ab29a247SBingbu Cao { 189ab29a247SBingbu Cao unsigned int mask = BUTTRESS_IU2CSECSR_IPC_PEER_ACKED_REG_VALID; 190ab29a247SBingbu Cao void __iomem *addr; 191ab29a247SBingbu Cao int ret; 192ab29a247SBingbu Cao u32 val; 193ab29a247SBingbu Cao 194ab29a247SBingbu Cao writel(BUTTRESS_IU2CSECSR_IPC_PEER_ASSERTED_REG_VALID_REQ, 195ab29a247SBingbu Cao isp->base + ipc->csr_out); 196ab29a247SBingbu Cao 197ab29a247SBingbu Cao addr = isp->base + ipc->csr_in; 198ab29a247SBingbu Cao ret = readl_poll_timeout(addr, val, val & mask, 200, 199ab29a247SBingbu Cao BUTTRESS_IPC_VALIDITY_TIMEOUT_US); 200ab29a247SBingbu Cao if (ret) { 201ab29a247SBingbu Cao dev_err(&isp->pdev->dev, "CSE validity timeout 0x%x\n", val); 202ab29a247SBingbu Cao ipu6_buttress_ipc_validity_close(isp, ipc); 203ab29a247SBingbu Cao } 204ab29a247SBingbu Cao 205ab29a247SBingbu Cao return ret; 206ab29a247SBingbu Cao } 207ab29a247SBingbu Cao 208ab29a247SBingbu Cao static void ipu6_buttress_ipc_recv(struct ipu6_device *isp, 209ab29a247SBingbu Cao struct ipu6_buttress_ipc *ipc, u32 *ipc_msg) 210ab29a247SBingbu Cao { 211ab29a247SBingbu Cao if (ipc_msg) 212ab29a247SBingbu Cao *ipc_msg = readl(isp->base + ipc->data0_in); 213ab29a247SBingbu Cao writel(0, isp->base + ipc->db0_in); 214ab29a247SBingbu Cao } 215ab29a247SBingbu Cao 216ab29a247SBingbu Cao static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp, 217ab29a247SBingbu Cao enum ipu6_buttress_ipc_domain ipc_domain, 218ab29a247SBingbu Cao struct ipu6_ipc_buttress_bulk_msg *msgs, 219ab29a247SBingbu Cao u32 size) 220ab29a247SBingbu Cao { 221ab29a247SBingbu Cao unsigned long tx_timeout_jiffies, rx_timeout_jiffies; 222ab29a247SBingbu Cao unsigned int i, retry = BUTTRESS_IPC_CMD_SEND_RETRY; 223ab29a247SBingbu Cao struct ipu6_buttress *b = &isp->buttress; 224ab29a247SBingbu Cao struct ipu6_buttress_ipc *ipc; 225ab29a247SBingbu Cao u32 val; 226ab29a247SBingbu Cao int ret; 227ab29a247SBingbu Cao int tout; 228ab29a247SBingbu Cao 229ab29a247SBingbu Cao ipc = ipc_domain == IPU6_BUTTRESS_IPC_CSE ? &b->cse : &b->ish; 230ab29a247SBingbu Cao 231ab29a247SBingbu Cao mutex_lock(&b->ipc_mutex); 232ab29a247SBingbu Cao 233ab29a247SBingbu Cao ret = ipu6_buttress_ipc_validity_open(isp, ipc); 234ab29a247SBingbu Cao if (ret) { 235ab29a247SBingbu Cao dev_err(&isp->pdev->dev, "IPC validity open failed\n"); 236ab29a247SBingbu Cao goto out; 237ab29a247SBingbu Cao } 238ab29a247SBingbu Cao 239ab29a247SBingbu Cao tx_timeout_jiffies = msecs_to_jiffies(BUTTRESS_IPC_TX_TIMEOUT_MS); 240ab29a247SBingbu Cao rx_timeout_jiffies = msecs_to_jiffies(BUTTRESS_IPC_RX_TIMEOUT_MS); 241ab29a247SBingbu Cao 242ab29a247SBingbu Cao for (i = 0; i < size; i++) { 243ab29a247SBingbu Cao reinit_completion(&ipc->send_complete); 244ab29a247SBingbu Cao if (msgs[i].require_resp) 245ab29a247SBingbu Cao reinit_completion(&ipc->recv_complete); 246ab29a247SBingbu Cao 247ab29a247SBingbu Cao dev_dbg(&isp->pdev->dev, "bulk IPC command: 0x%x\n", 248ab29a247SBingbu Cao msgs[i].cmd); 249ab29a247SBingbu Cao writel(msgs[i].cmd, isp->base + ipc->data0_out); 250ab29a247SBingbu Cao val = BUTTRESS_IU2CSEDB0_BUSY | msgs[i].cmd_size; 251ab29a247SBingbu Cao writel(val, isp->base + ipc->db0_out); 252ab29a247SBingbu Cao 253ab29a247SBingbu Cao tout = wait_for_completion_timeout(&ipc->send_complete, 254ab29a247SBingbu Cao tx_timeout_jiffies); 255ab29a247SBingbu Cao if (!tout) { 256ab29a247SBingbu Cao dev_err(&isp->pdev->dev, "send IPC response timeout\n"); 257ab29a247SBingbu Cao if (!retry--) { 258ab29a247SBingbu Cao ret = -ETIMEDOUT; 259ab29a247SBingbu Cao goto out; 260ab29a247SBingbu Cao } 261ab29a247SBingbu Cao 262ab29a247SBingbu Cao /* Try again if CSE is not responding on first try */ 263ab29a247SBingbu Cao writel(0, isp->base + ipc->db0_out); 264ab29a247SBingbu Cao i--; 265ab29a247SBingbu Cao continue; 266ab29a247SBingbu Cao } 267ab29a247SBingbu Cao 268ab29a247SBingbu Cao retry = BUTTRESS_IPC_CMD_SEND_RETRY; 269ab29a247SBingbu Cao 270ab29a247SBingbu Cao if (!msgs[i].require_resp) 271ab29a247SBingbu Cao continue; 272ab29a247SBingbu Cao 273ab29a247SBingbu Cao tout = wait_for_completion_timeout(&ipc->recv_complete, 274ab29a247SBingbu Cao rx_timeout_jiffies); 275ab29a247SBingbu Cao if (!tout) { 276ab29a247SBingbu Cao dev_err(&isp->pdev->dev, "recv IPC response timeout\n"); 277ab29a247SBingbu Cao ret = -ETIMEDOUT; 278ab29a247SBingbu Cao goto out; 279ab29a247SBingbu Cao } 280ab29a247SBingbu Cao 281ab29a247SBingbu Cao if (ipc->nack_mask && 282ab29a247SBingbu Cao (ipc->recv_data & ipc->nack_mask) == ipc->nack) { 283ab29a247SBingbu Cao dev_err(&isp->pdev->dev, 284ab29a247SBingbu Cao "IPC NACK for cmd 0x%x\n", msgs[i].cmd); 285ab29a247SBingbu Cao ret = -EIO; 286ab29a247SBingbu Cao goto out; 287ab29a247SBingbu Cao } 288ab29a247SBingbu Cao 289ab29a247SBingbu Cao if (ipc->recv_data != msgs[i].expected_resp) { 290ab29a247SBingbu Cao dev_err(&isp->pdev->dev, 291ab29a247SBingbu Cao "expected resp: 0x%x, IPC response: 0x%x ", 292ab29a247SBingbu Cao msgs[i].expected_resp, ipc->recv_data); 293ab29a247SBingbu Cao ret = -EIO; 294ab29a247SBingbu Cao goto out; 295ab29a247SBingbu Cao } 296ab29a247SBingbu Cao } 297ab29a247SBingbu Cao 298ab29a247SBingbu Cao dev_dbg(&isp->pdev->dev, "bulk IPC commands done\n"); 299ab29a247SBingbu Cao 300ab29a247SBingbu Cao out: 301ab29a247SBingbu Cao ipu6_buttress_ipc_validity_close(isp, ipc); 302ab29a247SBingbu Cao mutex_unlock(&b->ipc_mutex); 303ab29a247SBingbu Cao return ret; 304ab29a247SBingbu Cao } 305ab29a247SBingbu Cao 306ab29a247SBingbu Cao static int 307ab29a247SBingbu Cao ipu6_buttress_ipc_send(struct ipu6_device *isp, 308ab29a247SBingbu Cao enum ipu6_buttress_ipc_domain ipc_domain, 309ab29a247SBingbu Cao u32 ipc_msg, u32 size, bool require_resp, 310ab29a247SBingbu Cao u32 expected_resp) 311ab29a247SBingbu Cao { 312ab29a247SBingbu Cao struct ipu6_ipc_buttress_bulk_msg msg = { 313ab29a247SBingbu Cao .cmd = ipc_msg, 314ab29a247SBingbu Cao .cmd_size = size, 315ab29a247SBingbu Cao .require_resp = require_resp, 316ab29a247SBingbu Cao .expected_resp = expected_resp, 317ab29a247SBingbu Cao }; 318ab29a247SBingbu Cao 319ab29a247SBingbu Cao return ipu6_buttress_ipc_send_bulk(isp, ipc_domain, &msg, 1); 320ab29a247SBingbu Cao } 321ab29a247SBingbu Cao 322ab29a247SBingbu Cao static irqreturn_t ipu6_buttress_call_isr(struct ipu6_bus_device *adev) 323ab29a247SBingbu Cao { 324ab29a247SBingbu Cao irqreturn_t ret = IRQ_WAKE_THREAD; 325ab29a247SBingbu Cao 326ab29a247SBingbu Cao if (!adev || !adev->auxdrv || !adev->auxdrv_data) 327ab29a247SBingbu Cao return IRQ_NONE; 328ab29a247SBingbu Cao 329ab29a247SBingbu Cao if (adev->auxdrv_data->isr) 330ab29a247SBingbu Cao ret = adev->auxdrv_data->isr(adev); 331ab29a247SBingbu Cao 332ab29a247SBingbu Cao if (ret == IRQ_WAKE_THREAD && !adev->auxdrv_data->isr_threaded) 333ab29a247SBingbu Cao ret = IRQ_NONE; 334ab29a247SBingbu Cao 335ab29a247SBingbu Cao return ret; 336ab29a247SBingbu Cao } 337ab29a247SBingbu Cao 338ab29a247SBingbu Cao irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr) 339ab29a247SBingbu Cao { 340ab29a247SBingbu Cao struct ipu6_device *isp = isp_ptr; 341ab29a247SBingbu Cao struct ipu6_bus_device *adev[] = { isp->isys, isp->psys }; 342ab29a247SBingbu Cao struct ipu6_buttress *b = &isp->buttress; 343ab29a247SBingbu Cao u32 reg_irq_sts = BUTTRESS_REG_ISR_STATUS; 344ab29a247SBingbu Cao irqreturn_t ret = IRQ_NONE; 345ab29a247SBingbu Cao u32 disable_irqs = 0; 346ab29a247SBingbu Cao u32 irq_status; 347ab29a247SBingbu Cao u32 i, count = 0; 348ab29a247SBingbu Cao 349ab29a247SBingbu Cao pm_runtime_get_noresume(&isp->pdev->dev); 350ab29a247SBingbu Cao 351ab29a247SBingbu Cao irq_status = readl(isp->base + reg_irq_sts); 352ab29a247SBingbu Cao if (!irq_status) { 353ab29a247SBingbu Cao pm_runtime_put_noidle(&isp->pdev->dev); 354ab29a247SBingbu Cao return IRQ_NONE; 355ab29a247SBingbu Cao } 356ab29a247SBingbu Cao 357ab29a247SBingbu Cao do { 358ab29a247SBingbu Cao writel(irq_status, isp->base + BUTTRESS_REG_ISR_CLEAR); 359ab29a247SBingbu Cao 360ab29a247SBingbu Cao for (i = 0; i < ARRAY_SIZE(ipu6_adev_irq_mask); i++) { 361ab29a247SBingbu Cao irqreturn_t r = ipu6_buttress_call_isr(adev[i]); 362ab29a247SBingbu Cao 363ab29a247SBingbu Cao if (!(irq_status & ipu6_adev_irq_mask[i])) 364ab29a247SBingbu Cao continue; 365ab29a247SBingbu Cao 366ab29a247SBingbu Cao if (r == IRQ_WAKE_THREAD) { 367ab29a247SBingbu Cao ret = IRQ_WAKE_THREAD; 368ab29a247SBingbu Cao disable_irqs |= ipu6_adev_irq_mask[i]; 369ab29a247SBingbu Cao } else if (ret == IRQ_NONE && r == IRQ_HANDLED) { 370ab29a247SBingbu Cao ret = IRQ_HANDLED; 371ab29a247SBingbu Cao } 372ab29a247SBingbu Cao } 373ab29a247SBingbu Cao 374ab29a247SBingbu Cao if ((irq_status & BUTTRESS_EVENT) && ret == IRQ_NONE) 375ab29a247SBingbu Cao ret = IRQ_HANDLED; 376ab29a247SBingbu Cao 377ab29a247SBingbu Cao if (irq_status & BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING) { 378ab29a247SBingbu Cao dev_dbg(&isp->pdev->dev, 379ab29a247SBingbu Cao "BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING\n"); 380ab29a247SBingbu Cao ipu6_buttress_ipc_recv(isp, &b->cse, &b->cse.recv_data); 381ab29a247SBingbu Cao complete(&b->cse.recv_complete); 382ab29a247SBingbu Cao } 383ab29a247SBingbu Cao 384ab29a247SBingbu Cao if (irq_status & BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING) { 385ab29a247SBingbu Cao dev_dbg(&isp->pdev->dev, 386ab29a247SBingbu Cao "BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING\n"); 387ab29a247SBingbu Cao ipu6_buttress_ipc_recv(isp, &b->ish, &b->ish.recv_data); 388ab29a247SBingbu Cao complete(&b->ish.recv_complete); 389ab29a247SBingbu Cao } 390ab29a247SBingbu Cao 391ab29a247SBingbu Cao if (irq_status & BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE) { 392ab29a247SBingbu Cao dev_dbg(&isp->pdev->dev, 393ab29a247SBingbu Cao "BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE\n"); 394ab29a247SBingbu Cao complete(&b->cse.send_complete); 395ab29a247SBingbu Cao } 396ab29a247SBingbu Cao 397ab29a247SBingbu Cao if (irq_status & BUTTRESS_ISR_IPC_EXEC_DONE_BY_ISH) { 398ab29a247SBingbu Cao dev_dbg(&isp->pdev->dev, 399ab29a247SBingbu Cao "BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE\n"); 400ab29a247SBingbu Cao complete(&b->ish.send_complete); 401ab29a247SBingbu Cao } 402ab29a247SBingbu Cao 403ab29a247SBingbu Cao if (irq_status & BUTTRESS_ISR_SAI_VIOLATION && 404ab29a247SBingbu Cao ipu6_buttress_get_secure_mode(isp)) 405ab29a247SBingbu Cao dev_err(&isp->pdev->dev, 406ab29a247SBingbu Cao "BUTTRESS_ISR_SAI_VIOLATION\n"); 407ab29a247SBingbu Cao 408ab29a247SBingbu Cao if (irq_status & (BUTTRESS_ISR_IS_FATAL_MEM_ERR | 409ab29a247SBingbu Cao BUTTRESS_ISR_PS_FATAL_MEM_ERR)) 410ab29a247SBingbu Cao dev_err(&isp->pdev->dev, 411ab29a247SBingbu Cao "BUTTRESS_ISR_FATAL_MEM_ERR\n"); 412ab29a247SBingbu Cao 413ab29a247SBingbu Cao if (irq_status & BUTTRESS_ISR_UFI_ERROR) 414ab29a247SBingbu Cao dev_err(&isp->pdev->dev, "BUTTRESS_ISR_UFI_ERROR\n"); 415ab29a247SBingbu Cao 416ab29a247SBingbu Cao if (++count == BUTTRESS_MAX_CONSECUTIVE_IRQS) { 417ab29a247SBingbu Cao dev_err(&isp->pdev->dev, "too many consecutive IRQs\n"); 418ab29a247SBingbu Cao ret = IRQ_NONE; 419ab29a247SBingbu Cao break; 420ab29a247SBingbu Cao } 421ab29a247SBingbu Cao 422ab29a247SBingbu Cao irq_status = readl(isp->base + reg_irq_sts); 423ab29a247SBingbu Cao } while (irq_status); 424ab29a247SBingbu Cao 425ab29a247SBingbu Cao if (disable_irqs) 426ab29a247SBingbu Cao writel(BUTTRESS_IRQS & ~disable_irqs, 427ab29a247SBingbu Cao isp->base + BUTTRESS_REG_ISR_ENABLE); 428ab29a247SBingbu Cao 429ab29a247SBingbu Cao pm_runtime_put(&isp->pdev->dev); 430ab29a247SBingbu Cao 431ab29a247SBingbu Cao return ret; 432ab29a247SBingbu Cao } 433ab29a247SBingbu Cao 434ab29a247SBingbu Cao irqreturn_t ipu6_buttress_isr_threaded(int irq, void *isp_ptr) 435ab29a247SBingbu Cao { 436ab29a247SBingbu Cao struct ipu6_device *isp = isp_ptr; 437ab29a247SBingbu Cao struct ipu6_bus_device *adev[] = { isp->isys, isp->psys }; 438ab29a247SBingbu Cao const struct ipu6_auxdrv_data *drv_data = NULL; 439ab29a247SBingbu Cao irqreturn_t ret = IRQ_NONE; 440ab29a247SBingbu Cao unsigned int i; 441ab29a247SBingbu Cao 442ab29a247SBingbu Cao for (i = 0; i < ARRAY_SIZE(ipu6_adev_irq_mask) && adev[i]; i++) { 443ab29a247SBingbu Cao drv_data = adev[i]->auxdrv_data; 444ab29a247SBingbu Cao if (!drv_data) 445ab29a247SBingbu Cao continue; 446ab29a247SBingbu Cao 447ab29a247SBingbu Cao if (drv_data->wake_isr_thread && 448ab29a247SBingbu Cao drv_data->isr_threaded(adev[i]) == IRQ_HANDLED) 449ab29a247SBingbu Cao ret = IRQ_HANDLED; 450ab29a247SBingbu Cao } 451ab29a247SBingbu Cao 452ab29a247SBingbu Cao writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_ENABLE); 453ab29a247SBingbu Cao 454ab29a247SBingbu Cao return ret; 455ab29a247SBingbu Cao } 456ab29a247SBingbu Cao 457ab29a247SBingbu Cao int ipu6_buttress_power(struct device *dev, struct ipu6_buttress_ctrl *ctrl, 458ab29a247SBingbu Cao bool on) 459ab29a247SBingbu Cao { 460ab29a247SBingbu Cao struct ipu6_device *isp = to_ipu6_bus_device(dev)->isp; 461ab29a247SBingbu Cao u32 pwr_sts, val; 462ab29a247SBingbu Cao int ret; 463ab29a247SBingbu Cao 464ab29a247SBingbu Cao if (!ctrl) 465ab29a247SBingbu Cao return 0; 466ab29a247SBingbu Cao 467ab29a247SBingbu Cao mutex_lock(&isp->buttress.power_mutex); 468ab29a247SBingbu Cao 469ab29a247SBingbu Cao if (!on) { 470ab29a247SBingbu Cao val = 0; 471ab29a247SBingbu Cao pwr_sts = ctrl->pwr_sts_off << ctrl->pwr_sts_shift; 472ab29a247SBingbu Cao } else { 473ab29a247SBingbu Cao val = BUTTRESS_FREQ_CTL_START | 474ab29a247SBingbu Cao FIELD_PREP(BUTTRESS_FREQ_CTL_RATIO_MASK, 475ab29a247SBingbu Cao ctrl->ratio) | 476ab29a247SBingbu Cao FIELD_PREP(BUTTRESS_FREQ_CTL_QOS_FLOOR_MASK, 477ab29a247SBingbu Cao ctrl->qos_floor) | 478ab29a247SBingbu Cao BUTTRESS_FREQ_CTL_ICCMAX_LEVEL; 479ab29a247SBingbu Cao 480ab29a247SBingbu Cao pwr_sts = ctrl->pwr_sts_on << ctrl->pwr_sts_shift; 481ab29a247SBingbu Cao } 482ab29a247SBingbu Cao 483ab29a247SBingbu Cao writel(val, isp->base + ctrl->freq_ctl); 484ab29a247SBingbu Cao 485ab29a247SBingbu Cao ret = readl_poll_timeout(isp->base + BUTTRESS_REG_PWR_STATE, 486ab29a247SBingbu Cao val, (val & ctrl->pwr_sts_mask) == pwr_sts, 487ab29a247SBingbu Cao 100, BUTTRESS_POWER_TIMEOUT_US); 488ab29a247SBingbu Cao if (ret) 489ab29a247SBingbu Cao dev_err(&isp->pdev->dev, 490ab29a247SBingbu Cao "Change power status timeout with 0x%x\n", val); 491ab29a247SBingbu Cao 492ab29a247SBingbu Cao ctrl->started = !ret && on; 493ab29a247SBingbu Cao 494ab29a247SBingbu Cao mutex_unlock(&isp->buttress.power_mutex); 495ab29a247SBingbu Cao 496ab29a247SBingbu Cao return ret; 497ab29a247SBingbu Cao } 498ab29a247SBingbu Cao 499ab29a247SBingbu Cao bool ipu6_buttress_get_secure_mode(struct ipu6_device *isp) 500ab29a247SBingbu Cao { 501ab29a247SBingbu Cao u32 val; 502ab29a247SBingbu Cao 503ab29a247SBingbu Cao val = readl(isp->base + BUTTRESS_REG_SECURITY_CTL); 504ab29a247SBingbu Cao 505ab29a247SBingbu Cao return val & BUTTRESS_SECURITY_CTL_FW_SECURE_MODE; 506ab29a247SBingbu Cao } 507ab29a247SBingbu Cao 508ab29a247SBingbu Cao bool ipu6_buttress_auth_done(struct ipu6_device *isp) 509ab29a247SBingbu Cao { 510ab29a247SBingbu Cao u32 val; 511ab29a247SBingbu Cao 512ab29a247SBingbu Cao if (!isp->secure_mode) 513ab29a247SBingbu Cao return true; 514ab29a247SBingbu Cao 515ab29a247SBingbu Cao val = readl(isp->base + BUTTRESS_REG_SECURITY_CTL); 516ab29a247SBingbu Cao val = FIELD_GET(BUTTRESS_SECURITY_CTL_FW_SETUP_MASK, val); 517ab29a247SBingbu Cao 518ab29a247SBingbu Cao return val == BUTTRESS_SECURITY_CTL_AUTH_DONE; 519ab29a247SBingbu Cao } 520ab29a247SBingbu Cao EXPORT_SYMBOL_NS_GPL(ipu6_buttress_auth_done, INTEL_IPU6); 521ab29a247SBingbu Cao 522ab29a247SBingbu Cao int ipu6_buttress_reset_authentication(struct ipu6_device *isp) 523ab29a247SBingbu Cao { 524ab29a247SBingbu Cao int ret; 525ab29a247SBingbu Cao u32 val; 526ab29a247SBingbu Cao 527ab29a247SBingbu Cao if (!isp->secure_mode) { 528ab29a247SBingbu Cao dev_dbg(&isp->pdev->dev, "Skip auth for non-secure mode\n"); 529ab29a247SBingbu Cao return 0; 530ab29a247SBingbu Cao } 531ab29a247SBingbu Cao 532ab29a247SBingbu Cao writel(BUTTRESS_FW_RESET_CTL_START, isp->base + 533ab29a247SBingbu Cao BUTTRESS_REG_FW_RESET_CTL); 534ab29a247SBingbu Cao 535ab29a247SBingbu Cao ret = readl_poll_timeout(isp->base + BUTTRESS_REG_FW_RESET_CTL, val, 536ab29a247SBingbu Cao val & BUTTRESS_FW_RESET_CTL_DONE, 500, 537ab29a247SBingbu Cao BUTTRESS_CSE_FWRESET_TIMEOUT_US); 538ab29a247SBingbu Cao if (ret) { 539ab29a247SBingbu Cao dev_err(&isp->pdev->dev, 540ab29a247SBingbu Cao "Time out while resetting authentication state\n"); 541ab29a247SBingbu Cao return ret; 542ab29a247SBingbu Cao } 543ab29a247SBingbu Cao 544ab29a247SBingbu Cao dev_dbg(&isp->pdev->dev, "FW reset for authentication done\n"); 545ab29a247SBingbu Cao writel(0, isp->base + BUTTRESS_REG_FW_RESET_CTL); 546ab29a247SBingbu Cao /* leave some time for HW restore */ 547ab29a247SBingbu Cao usleep_range(800, 1000); 548ab29a247SBingbu Cao 549ab29a247SBingbu Cao return 0; 550ab29a247SBingbu Cao } 551ab29a247SBingbu Cao 552ab29a247SBingbu Cao int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys, 553ab29a247SBingbu Cao const struct firmware *fw, struct sg_table *sgt) 554ab29a247SBingbu Cao { 555*8a09bb1bSSakari Ailus bool is_vmalloc = is_vmalloc_addr(fw->data); 556ab29a247SBingbu Cao struct page **pages; 557ab29a247SBingbu Cao const void *addr; 558ab29a247SBingbu Cao unsigned long n_pages; 559ab29a247SBingbu Cao unsigned int i; 560ab29a247SBingbu Cao int ret; 561ab29a247SBingbu Cao 562*8a09bb1bSSakari Ailus if (!is_vmalloc && !virt_addr_valid(fw->data)) 563*8a09bb1bSSakari Ailus return -EDOM; 564*8a09bb1bSSakari Ailus 565ab29a247SBingbu Cao n_pages = PHYS_PFN(PAGE_ALIGN(fw->size)); 566ab29a247SBingbu Cao 567ab29a247SBingbu Cao pages = kmalloc_array(n_pages, sizeof(*pages), GFP_KERNEL); 568ab29a247SBingbu Cao if (!pages) 569ab29a247SBingbu Cao return -ENOMEM; 570ab29a247SBingbu Cao 571ab29a247SBingbu Cao addr = fw->data; 572ab29a247SBingbu Cao for (i = 0; i < n_pages; i++) { 573*8a09bb1bSSakari Ailus struct page *p = is_vmalloc ? 574*8a09bb1bSSakari Ailus vmalloc_to_page(addr) : virt_to_page(addr); 575ab29a247SBingbu Cao 576ab29a247SBingbu Cao if (!p) { 577ab29a247SBingbu Cao ret = -ENOMEM; 578ab29a247SBingbu Cao goto out; 579ab29a247SBingbu Cao } 580ab29a247SBingbu Cao pages[i] = p; 581ab29a247SBingbu Cao addr += PAGE_SIZE; 582ab29a247SBingbu Cao } 583ab29a247SBingbu Cao 584ab29a247SBingbu Cao ret = sg_alloc_table_from_pages(sgt, pages, n_pages, 0, fw->size, 585ab29a247SBingbu Cao GFP_KERNEL); 586ab29a247SBingbu Cao if (ret) { 587ab29a247SBingbu Cao ret = -ENOMEM; 588ab29a247SBingbu Cao goto out; 589ab29a247SBingbu Cao } 590ab29a247SBingbu Cao 591ab29a247SBingbu Cao ret = dma_map_sgtable(&sys->auxdev.dev, sgt, DMA_TO_DEVICE, 0); 592ab29a247SBingbu Cao if (ret < 0) { 593ab29a247SBingbu Cao ret = -ENOMEM; 594ab29a247SBingbu Cao sg_free_table(sgt); 595ab29a247SBingbu Cao goto out; 596ab29a247SBingbu Cao } 597ab29a247SBingbu Cao 598ab29a247SBingbu Cao dma_sync_sgtable_for_device(&sys->auxdev.dev, sgt, DMA_TO_DEVICE); 599ab29a247SBingbu Cao 600ab29a247SBingbu Cao out: 601ab29a247SBingbu Cao kfree(pages); 602ab29a247SBingbu Cao 603ab29a247SBingbu Cao return ret; 604ab29a247SBingbu Cao } 605ab29a247SBingbu Cao EXPORT_SYMBOL_NS_GPL(ipu6_buttress_map_fw_image, INTEL_IPU6); 606ab29a247SBingbu Cao 607ab29a247SBingbu Cao void ipu6_buttress_unmap_fw_image(struct ipu6_bus_device *sys, 608ab29a247SBingbu Cao struct sg_table *sgt) 609ab29a247SBingbu Cao { 610ab29a247SBingbu Cao dma_unmap_sgtable(&sys->auxdev.dev, sgt, DMA_TO_DEVICE, 0); 611ab29a247SBingbu Cao sg_free_table(sgt); 612ab29a247SBingbu Cao } 613ab29a247SBingbu Cao EXPORT_SYMBOL_NS_GPL(ipu6_buttress_unmap_fw_image, INTEL_IPU6); 614ab29a247SBingbu Cao 615ab29a247SBingbu Cao int ipu6_buttress_authenticate(struct ipu6_device *isp) 616ab29a247SBingbu Cao { 617ab29a247SBingbu Cao struct ipu6_buttress *b = &isp->buttress; 618ab29a247SBingbu Cao struct ipu6_psys_pdata *psys_pdata; 619ab29a247SBingbu Cao u32 data, mask, done, fail; 620ab29a247SBingbu Cao int ret; 621ab29a247SBingbu Cao 622ab29a247SBingbu Cao if (!isp->secure_mode) { 623ab29a247SBingbu Cao dev_dbg(&isp->pdev->dev, "Skip auth for non-secure mode\n"); 624ab29a247SBingbu Cao return 0; 625ab29a247SBingbu Cao } 626ab29a247SBingbu Cao 627ab29a247SBingbu Cao psys_pdata = isp->psys->pdata; 628ab29a247SBingbu Cao 629ab29a247SBingbu Cao mutex_lock(&b->auth_mutex); 630ab29a247SBingbu Cao 631ab29a247SBingbu Cao if (ipu6_buttress_auth_done(isp)) { 632ab29a247SBingbu Cao ret = 0; 633ab29a247SBingbu Cao goto out_unlock; 634ab29a247SBingbu Cao } 635ab29a247SBingbu Cao 636ab29a247SBingbu Cao /* 637ab29a247SBingbu Cao * Write address of FIT table to FW_SOURCE register 638ab29a247SBingbu Cao * Let's use fw address. I.e. not using FIT table yet 639ab29a247SBingbu Cao */ 640ab29a247SBingbu Cao data = lower_32_bits(isp->psys->pkg_dir_dma_addr); 641ab29a247SBingbu Cao writel(data, isp->base + BUTTRESS_REG_FW_SOURCE_BASE_LO); 642ab29a247SBingbu Cao 643ab29a247SBingbu Cao data = upper_32_bits(isp->psys->pkg_dir_dma_addr); 644ab29a247SBingbu Cao writel(data, isp->base + BUTTRESS_REG_FW_SOURCE_BASE_HI); 645ab29a247SBingbu Cao 646ab29a247SBingbu Cao /* 647ab29a247SBingbu Cao * Write boot_load into IU2CSEDATA0 648ab29a247SBingbu Cao * Write sizeof(boot_load) | 0x2 << CLIENT_ID to 649ab29a247SBingbu Cao * IU2CSEDB.IU2CSECMD and set IU2CSEDB.IU2CSEBUSY as 650ab29a247SBingbu Cao */ 651ab29a247SBingbu Cao dev_info(&isp->pdev->dev, "Sending BOOT_LOAD to CSE\n"); 652ab29a247SBingbu Cao 653ab29a247SBingbu Cao ret = ipu6_buttress_ipc_send(isp, IPU6_BUTTRESS_IPC_CSE, 654ab29a247SBingbu Cao BUTTRESS_IU2CSEDATA0_IPC_BOOT_LOAD, 655ab29a247SBingbu Cao 1, true, 656ab29a247SBingbu Cao BUTTRESS_CSE2IUDATA0_IPC_BOOT_LOAD_DONE); 657ab29a247SBingbu Cao if (ret) { 658ab29a247SBingbu Cao dev_err(&isp->pdev->dev, "CSE boot_load failed\n"); 659ab29a247SBingbu Cao goto out_unlock; 660ab29a247SBingbu Cao } 661ab29a247SBingbu Cao 662ab29a247SBingbu Cao mask = BUTTRESS_SECURITY_CTL_FW_SETUP_MASK; 663ab29a247SBingbu Cao done = BUTTRESS_SECURITY_CTL_FW_SETUP_DONE; 664ab29a247SBingbu Cao fail = BUTTRESS_SECURITY_CTL_AUTH_FAILED; 665ab29a247SBingbu Cao ret = readl_poll_timeout(isp->base + BUTTRESS_REG_SECURITY_CTL, data, 666ab29a247SBingbu Cao ((data & mask) == done || 667ab29a247SBingbu Cao (data & mask) == fail), 500, 668ab29a247SBingbu Cao BUTTRESS_CSE_BOOTLOAD_TIMEOUT_US); 669ab29a247SBingbu Cao if (ret) { 670ab29a247SBingbu Cao dev_err(&isp->pdev->dev, "CSE boot_load timeout\n"); 671ab29a247SBingbu Cao goto out_unlock; 672ab29a247SBingbu Cao } 673ab29a247SBingbu Cao 674ab29a247SBingbu Cao if ((data & mask) == fail) { 675ab29a247SBingbu Cao dev_err(&isp->pdev->dev, "CSE auth failed\n"); 676ab29a247SBingbu Cao ret = -EINVAL; 677ab29a247SBingbu Cao goto out_unlock; 678ab29a247SBingbu Cao } 679ab29a247SBingbu Cao 680ab29a247SBingbu Cao ret = readl_poll_timeout(psys_pdata->base + BOOTLOADER_STATUS_OFFSET, 681ab29a247SBingbu Cao data, data == BOOTLOADER_MAGIC_KEY, 500, 682ab29a247SBingbu Cao BUTTRESS_CSE_BOOTLOAD_TIMEOUT_US); 683ab29a247SBingbu Cao if (ret) { 684ab29a247SBingbu Cao dev_err(&isp->pdev->dev, "Unexpected magic number 0x%x\n", 685ab29a247SBingbu Cao data); 686ab29a247SBingbu Cao goto out_unlock; 687ab29a247SBingbu Cao } 688ab29a247SBingbu Cao 689ab29a247SBingbu Cao /* 690ab29a247SBingbu Cao * Write authenticate_run into IU2CSEDATA0 691ab29a247SBingbu Cao * Write sizeof(boot_load) | 0x2 << CLIENT_ID to 692ab29a247SBingbu Cao * IU2CSEDB.IU2CSECMD and set IU2CSEDB.IU2CSEBUSY as 693ab29a247SBingbu Cao */ 694ab29a247SBingbu Cao dev_info(&isp->pdev->dev, "Sending AUTHENTICATE_RUN to CSE\n"); 695ab29a247SBingbu Cao ret = ipu6_buttress_ipc_send(isp, IPU6_BUTTRESS_IPC_CSE, 696ab29a247SBingbu Cao BUTTRESS_IU2CSEDATA0_IPC_AUTH_RUN, 697ab29a247SBingbu Cao 1, true, 698ab29a247SBingbu Cao BUTTRESS_CSE2IUDATA0_IPC_AUTH_RUN_DONE); 699ab29a247SBingbu Cao if (ret) { 700ab29a247SBingbu Cao dev_err(&isp->pdev->dev, "CSE authenticate_run failed\n"); 701ab29a247SBingbu Cao goto out_unlock; 702ab29a247SBingbu Cao } 703ab29a247SBingbu Cao 704ab29a247SBingbu Cao done = BUTTRESS_SECURITY_CTL_AUTH_DONE; 705ab29a247SBingbu Cao ret = readl_poll_timeout(isp->base + BUTTRESS_REG_SECURITY_CTL, data, 706ab29a247SBingbu Cao ((data & mask) == done || 707ab29a247SBingbu Cao (data & mask) == fail), 500, 708ab29a247SBingbu Cao BUTTRESS_CSE_AUTHENTICATE_TIMEOUT_US); 709ab29a247SBingbu Cao if (ret) { 710ab29a247SBingbu Cao dev_err(&isp->pdev->dev, "CSE authenticate timeout\n"); 711ab29a247SBingbu Cao goto out_unlock; 712ab29a247SBingbu Cao } 713ab29a247SBingbu Cao 714ab29a247SBingbu Cao if ((data & mask) == fail) { 715ab29a247SBingbu Cao dev_err(&isp->pdev->dev, "CSE boot_load failed\n"); 716ab29a247SBingbu Cao ret = -EINVAL; 717ab29a247SBingbu Cao goto out_unlock; 718ab29a247SBingbu Cao } 719ab29a247SBingbu Cao 720ab29a247SBingbu Cao dev_info(&isp->pdev->dev, "CSE authenticate_run done\n"); 721ab29a247SBingbu Cao 722ab29a247SBingbu Cao out_unlock: 723ab29a247SBingbu Cao mutex_unlock(&b->auth_mutex); 724ab29a247SBingbu Cao 725ab29a247SBingbu Cao return ret; 726ab29a247SBingbu Cao } 727ab29a247SBingbu Cao 728ab29a247SBingbu Cao static int ipu6_buttress_send_tsc_request(struct ipu6_device *isp) 729ab29a247SBingbu Cao { 730ab29a247SBingbu Cao u32 val, mask, done; 731ab29a247SBingbu Cao int ret; 732ab29a247SBingbu Cao 733ab29a247SBingbu Cao mask = BUTTRESS_PWR_STATE_HH_STATUS_MASK; 734ab29a247SBingbu Cao 735ab29a247SBingbu Cao writel(BUTTRESS_FABRIC_CMD_START_TSC_SYNC, 736ab29a247SBingbu Cao isp->base + BUTTRESS_REG_FABRIC_CMD); 737ab29a247SBingbu Cao 738ab29a247SBingbu Cao val = readl(isp->base + BUTTRESS_REG_PWR_STATE); 739ab29a247SBingbu Cao val = FIELD_GET(mask, val); 740ab29a247SBingbu Cao if (val == BUTTRESS_PWR_STATE_HH_STATE_ERR) { 741ab29a247SBingbu Cao dev_err(&isp->pdev->dev, "Start tsc sync failed\n"); 742ab29a247SBingbu Cao return -EINVAL; 743ab29a247SBingbu Cao } 744ab29a247SBingbu Cao 745ab29a247SBingbu Cao done = BUTTRESS_PWR_STATE_HH_STATE_DONE; 746ab29a247SBingbu Cao ret = readl_poll_timeout(isp->base + BUTTRESS_REG_PWR_STATE, val, 747ab29a247SBingbu Cao FIELD_GET(mask, val) == done, 500, 748ab29a247SBingbu Cao BUTTRESS_TSC_SYNC_TIMEOUT_US); 749ab29a247SBingbu Cao if (ret) 750ab29a247SBingbu Cao dev_err(&isp->pdev->dev, "Start tsc sync timeout\n"); 751ab29a247SBingbu Cao 752ab29a247SBingbu Cao return ret; 753ab29a247SBingbu Cao } 754ab29a247SBingbu Cao 755ab29a247SBingbu Cao int ipu6_buttress_start_tsc_sync(struct ipu6_device *isp) 756ab29a247SBingbu Cao { 757ab29a247SBingbu Cao unsigned int i; 758ab29a247SBingbu Cao 759ab29a247SBingbu Cao for (i = 0; i < BUTTRESS_TSC_SYNC_RESET_TRIAL_MAX; i++) { 760ab29a247SBingbu Cao u32 val; 761ab29a247SBingbu Cao int ret; 762ab29a247SBingbu Cao 763ab29a247SBingbu Cao ret = ipu6_buttress_send_tsc_request(isp); 764ab29a247SBingbu Cao if (ret != -ETIMEDOUT) 765ab29a247SBingbu Cao return ret; 766ab29a247SBingbu Cao 767ab29a247SBingbu Cao val = readl(isp->base + BUTTRESS_REG_TSW_CTL); 768ab29a247SBingbu Cao val = val | BUTTRESS_TSW_CTL_SOFT_RESET; 769ab29a247SBingbu Cao writel(val, isp->base + BUTTRESS_REG_TSW_CTL); 770ab29a247SBingbu Cao val = val & ~BUTTRESS_TSW_CTL_SOFT_RESET; 771ab29a247SBingbu Cao writel(val, isp->base + BUTTRESS_REG_TSW_CTL); 772ab29a247SBingbu Cao } 773ab29a247SBingbu Cao 774ab29a247SBingbu Cao dev_err(&isp->pdev->dev, "TSC sync failed (timeout)\n"); 775ab29a247SBingbu Cao 776ab29a247SBingbu Cao return -ETIMEDOUT; 777ab29a247SBingbu Cao } 778ab29a247SBingbu Cao EXPORT_SYMBOL_NS_GPL(ipu6_buttress_start_tsc_sync, INTEL_IPU6); 779ab29a247SBingbu Cao 780ab29a247SBingbu Cao void ipu6_buttress_tsc_read(struct ipu6_device *isp, u64 *val) 781ab29a247SBingbu Cao { 782ab29a247SBingbu Cao u32 tsc_hi_1, tsc_hi_2, tsc_lo; 783ab29a247SBingbu Cao unsigned long flags; 784ab29a247SBingbu Cao 785ab29a247SBingbu Cao local_irq_save(flags); 786ab29a247SBingbu Cao tsc_hi_1 = readl(isp->base + BUTTRESS_REG_TSC_HI); 787ab29a247SBingbu Cao tsc_lo = readl(isp->base + BUTTRESS_REG_TSC_LO); 788ab29a247SBingbu Cao tsc_hi_2 = readl(isp->base + BUTTRESS_REG_TSC_HI); 789ab29a247SBingbu Cao if (tsc_hi_1 == tsc_hi_2) { 790ab29a247SBingbu Cao *val = (u64)tsc_hi_1 << 32 | tsc_lo; 791ab29a247SBingbu Cao } else { 792ab29a247SBingbu Cao /* Check if TSC has rolled over */ 793ab29a247SBingbu Cao if (tsc_lo & BIT(31)) 794ab29a247SBingbu Cao *val = (u64)tsc_hi_1 << 32 | tsc_lo; 795ab29a247SBingbu Cao else 796ab29a247SBingbu Cao *val = (u64)tsc_hi_2 << 32 | tsc_lo; 797ab29a247SBingbu Cao } 798ab29a247SBingbu Cao local_irq_restore(flags); 799ab29a247SBingbu Cao } 800ab29a247SBingbu Cao EXPORT_SYMBOL_NS_GPL(ipu6_buttress_tsc_read, INTEL_IPU6); 801ab29a247SBingbu Cao 802ab29a247SBingbu Cao u64 ipu6_buttress_tsc_ticks_to_ns(u64 ticks, const struct ipu6_device *isp) 803ab29a247SBingbu Cao { 804ab29a247SBingbu Cao u64 ns = ticks * 10000; 805ab29a247SBingbu Cao 806ab29a247SBingbu Cao /* 807ab29a247SBingbu Cao * converting TSC tick count to ns is calculated by: 808ab29a247SBingbu Cao * Example (TSC clock frequency is 19.2MHz): 809ab29a247SBingbu Cao * ns = ticks * 1000 000 000 / 19.2Mhz 810ab29a247SBingbu Cao * = ticks * 1000 000 000 / 19200000Hz 811ab29a247SBingbu Cao * = ticks * 10000 / 192 ns 812ab29a247SBingbu Cao */ 813ab29a247SBingbu Cao return div_u64(ns, isp->buttress.ref_clk); 814ab29a247SBingbu Cao } 815ab29a247SBingbu Cao EXPORT_SYMBOL_NS_GPL(ipu6_buttress_tsc_ticks_to_ns, INTEL_IPU6); 816ab29a247SBingbu Cao 817ab29a247SBingbu Cao void ipu6_buttress_restore(struct ipu6_device *isp) 818ab29a247SBingbu Cao { 819ab29a247SBingbu Cao struct ipu6_buttress *b = &isp->buttress; 820ab29a247SBingbu Cao 821ab29a247SBingbu Cao writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_CLEAR); 822ab29a247SBingbu Cao writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_ENABLE); 823ab29a247SBingbu Cao writel(b->wdt_cached_value, isp->base + BUTTRESS_REG_WDT); 824ab29a247SBingbu Cao } 825ab29a247SBingbu Cao 826ab29a247SBingbu Cao int ipu6_buttress_init(struct ipu6_device *isp) 827ab29a247SBingbu Cao { 828ab29a247SBingbu Cao int ret, ipc_reset_retry = BUTTRESS_CSE_IPC_RESET_RETRY; 829ab29a247SBingbu Cao struct ipu6_buttress *b = &isp->buttress; 830ab29a247SBingbu Cao u32 val; 831ab29a247SBingbu Cao 832ab29a247SBingbu Cao mutex_init(&b->power_mutex); 833ab29a247SBingbu Cao mutex_init(&b->auth_mutex); 834ab29a247SBingbu Cao mutex_init(&b->cons_mutex); 835ab29a247SBingbu Cao mutex_init(&b->ipc_mutex); 836ab29a247SBingbu Cao init_completion(&b->ish.send_complete); 837ab29a247SBingbu Cao init_completion(&b->cse.send_complete); 838ab29a247SBingbu Cao init_completion(&b->ish.recv_complete); 839ab29a247SBingbu Cao init_completion(&b->cse.recv_complete); 840ab29a247SBingbu Cao 841ab29a247SBingbu Cao b->cse.nack = BUTTRESS_CSE2IUDATA0_IPC_NACK; 842ab29a247SBingbu Cao b->cse.nack_mask = BUTTRESS_CSE2IUDATA0_IPC_NACK_MASK; 843ab29a247SBingbu Cao b->cse.csr_in = BUTTRESS_REG_CSE2IUCSR; 844ab29a247SBingbu Cao b->cse.csr_out = BUTTRESS_REG_IU2CSECSR; 845ab29a247SBingbu Cao b->cse.db0_in = BUTTRESS_REG_CSE2IUDB0; 846ab29a247SBingbu Cao b->cse.db0_out = BUTTRESS_REG_IU2CSEDB0; 847ab29a247SBingbu Cao b->cse.data0_in = BUTTRESS_REG_CSE2IUDATA0; 848ab29a247SBingbu Cao b->cse.data0_out = BUTTRESS_REG_IU2CSEDATA0; 849ab29a247SBingbu Cao 850ab29a247SBingbu Cao /* no ISH on IPU6 */ 851ab29a247SBingbu Cao memset(&b->ish, 0, sizeof(b->ish)); 852ab29a247SBingbu Cao INIT_LIST_HEAD(&b->constraints); 853ab29a247SBingbu Cao 854ab29a247SBingbu Cao isp->secure_mode = ipu6_buttress_get_secure_mode(isp); 855ab29a247SBingbu Cao dev_info(&isp->pdev->dev, "IPU6 in %s mode touch 0x%x mask 0x%x\n", 856ab29a247SBingbu Cao isp->secure_mode ? "secure" : "non-secure", 857ab29a247SBingbu Cao readl(isp->base + BUTTRESS_REG_SECURITY_TOUCH), 858ab29a247SBingbu Cao readl(isp->base + BUTTRESS_REG_CAMERA_MASK)); 859ab29a247SBingbu Cao 860ab29a247SBingbu Cao b->wdt_cached_value = readl(isp->base + BUTTRESS_REG_WDT); 861ab29a247SBingbu Cao writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_CLEAR); 862ab29a247SBingbu Cao writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_ENABLE); 863ab29a247SBingbu Cao 864ab29a247SBingbu Cao /* get ref_clk frequency by reading the indication in btrs control */ 865ab29a247SBingbu Cao val = readl(isp->base + BUTTRESS_REG_BTRS_CTRL); 866ab29a247SBingbu Cao val = FIELD_GET(BUTTRESS_REG_BTRS_CTRL_REF_CLK_IND, val); 867ab29a247SBingbu Cao 868ab29a247SBingbu Cao switch (val) { 869ab29a247SBingbu Cao case 0x0: 870ab29a247SBingbu Cao b->ref_clk = 240; 871ab29a247SBingbu Cao break; 872ab29a247SBingbu Cao case 0x1: 873ab29a247SBingbu Cao b->ref_clk = 192; 874ab29a247SBingbu Cao break; 875ab29a247SBingbu Cao case 0x2: 876ab29a247SBingbu Cao b->ref_clk = 384; 877ab29a247SBingbu Cao break; 878ab29a247SBingbu Cao default: 879ab29a247SBingbu Cao dev_warn(&isp->pdev->dev, 880ab29a247SBingbu Cao "Unsupported ref clock, use 19.2Mhz by default.\n"); 881ab29a247SBingbu Cao b->ref_clk = 192; 882ab29a247SBingbu Cao break; 883ab29a247SBingbu Cao } 884ab29a247SBingbu Cao 885ab29a247SBingbu Cao /* Retry couple of times in case of CSE initialization is delayed */ 886ab29a247SBingbu Cao do { 887ab29a247SBingbu Cao ret = ipu6_buttress_ipc_reset(isp, &b->cse); 888ab29a247SBingbu Cao if (ret) { 889ab29a247SBingbu Cao dev_warn(&isp->pdev->dev, 890ab29a247SBingbu Cao "IPC reset protocol failed, retrying\n"); 891ab29a247SBingbu Cao } else { 892ab29a247SBingbu Cao dev_dbg(&isp->pdev->dev, "IPC reset done\n"); 893ab29a247SBingbu Cao return 0; 894ab29a247SBingbu Cao } 895ab29a247SBingbu Cao } while (ipc_reset_retry--); 896ab29a247SBingbu Cao 897ab29a247SBingbu Cao dev_err(&isp->pdev->dev, "IPC reset protocol failed\n"); 898ab29a247SBingbu Cao 899ab29a247SBingbu Cao mutex_destroy(&b->power_mutex); 900ab29a247SBingbu Cao mutex_destroy(&b->auth_mutex); 901ab29a247SBingbu Cao mutex_destroy(&b->cons_mutex); 902ab29a247SBingbu Cao mutex_destroy(&b->ipc_mutex); 903ab29a247SBingbu Cao 904ab29a247SBingbu Cao return ret; 905ab29a247SBingbu Cao } 906ab29a247SBingbu Cao 907ab29a247SBingbu Cao void ipu6_buttress_exit(struct ipu6_device *isp) 908ab29a247SBingbu Cao { 909ab29a247SBingbu Cao struct ipu6_buttress *b = &isp->buttress; 910ab29a247SBingbu Cao 911ab29a247SBingbu Cao writel(0, isp->base + BUTTRESS_REG_ISR_ENABLE); 912ab29a247SBingbu Cao 913ab29a247SBingbu Cao mutex_destroy(&b->power_mutex); 914ab29a247SBingbu Cao mutex_destroy(&b->auth_mutex); 915ab29a247SBingbu Cao mutex_destroy(&b->cons_mutex); 916ab29a247SBingbu Cao mutex_destroy(&b->ipc_mutex); 917ab29a247SBingbu Cao } 918