18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2013 Freescale Semiconductor, Inc. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "fsl-pamu: %s: " fmt, __func__ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "fsl_pamu.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/fsl/guts.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/genalloc.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <asm/mpc85xx.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* define indexes for each operation mapping scenario */ 188c2ecf20Sopenharmony_ci#define OMI_QMAN 0x00 198c2ecf20Sopenharmony_ci#define OMI_FMAN 0x01 208c2ecf20Sopenharmony_ci#define OMI_QMAN_PRIV 0x02 218c2ecf20Sopenharmony_ci#define OMI_CAAM 0x03 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define make64(high, low) (((u64)(high) << 32) | (low)) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistruct pamu_isr_data { 268c2ecf20Sopenharmony_ci void __iomem *pamu_reg_base; /* Base address of PAMU regs */ 278c2ecf20Sopenharmony_ci unsigned int count; /* The number of PAMUs */ 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic struct paace *ppaact; 318c2ecf20Sopenharmony_cistatic struct paace *spaact; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic bool probed; /* Has PAMU been probed? */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * Table for matching compatible strings, for device tree 378c2ecf20Sopenharmony_ci * guts node, for QorIQ SOCs. 388c2ecf20Sopenharmony_ci * "fsl,qoriq-device-config-2.0" corresponds to T4 & B4 398c2ecf20Sopenharmony_ci * SOCs. For the older SOCs "fsl,qoriq-device-config-1.0" 408c2ecf20Sopenharmony_ci * string would be used. 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_cistatic const struct of_device_id guts_device_ids[] = { 438c2ecf20Sopenharmony_ci { .compatible = "fsl,qoriq-device-config-1.0", }, 448c2ecf20Sopenharmony_ci { .compatible = "fsl,qoriq-device-config-2.0", }, 458c2ecf20Sopenharmony_ci {} 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* 498c2ecf20Sopenharmony_ci * Table for matching compatible strings, for device tree 508c2ecf20Sopenharmony_ci * L3 cache controller node. 518c2ecf20Sopenharmony_ci * "fsl,t4240-l3-cache-controller" corresponds to T4, 528c2ecf20Sopenharmony_ci * "fsl,b4860-l3-cache-controller" corresponds to B4 & 538c2ecf20Sopenharmony_ci * "fsl,p4080-l3-cache-controller" corresponds to other, 548c2ecf20Sopenharmony_ci * SOCs. 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_cistatic const struct of_device_id l3_device_ids[] = { 578c2ecf20Sopenharmony_ci { .compatible = "fsl,t4240-l3-cache-controller", }, 588c2ecf20Sopenharmony_ci { .compatible = "fsl,b4860-l3-cache-controller", }, 598c2ecf20Sopenharmony_ci { .compatible = "fsl,p4080-l3-cache-controller", }, 608c2ecf20Sopenharmony_ci {} 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* maximum subwindows permitted per liodn */ 648c2ecf20Sopenharmony_cistatic u32 max_subwindow_count; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* Pool for fspi allocation */ 678c2ecf20Sopenharmony_cistatic struct gen_pool *spaace_pool; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/** 708c2ecf20Sopenharmony_ci * pamu_get_max_subwin_cnt() - Return the maximum supported 718c2ecf20Sopenharmony_ci * subwindow count per liodn. 728c2ecf20Sopenharmony_ci * 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_ciu32 pamu_get_max_subwin_cnt(void) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci return max_subwindow_count; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/** 808c2ecf20Sopenharmony_ci * pamu_get_ppaace() - Return the primary PACCE 818c2ecf20Sopenharmony_ci * @liodn: liodn PAACT index for desired PAACE 828c2ecf20Sopenharmony_ci * 838c2ecf20Sopenharmony_ci * Returns the ppace pointer upon success else return 848c2ecf20Sopenharmony_ci * null. 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_cistatic struct paace *pamu_get_ppaace(int liodn) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci if (!ppaact || liodn >= PAACE_NUMBER_ENTRIES) { 898c2ecf20Sopenharmony_ci pr_debug("PPAACT doesn't exist\n"); 908c2ecf20Sopenharmony_ci return NULL; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return &ppaact[liodn]; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/** 978c2ecf20Sopenharmony_ci * pamu_enable_liodn() - Set valid bit of PACCE 988c2ecf20Sopenharmony_ci * @liodn: liodn PAACT index for desired PAACE 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * Returns 0 upon success else error code < 0 returned 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ciint pamu_enable_liodn(int liodn) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct paace *ppaace; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci ppaace = pamu_get_ppaace(liodn); 1078c2ecf20Sopenharmony_ci if (!ppaace) { 1088c2ecf20Sopenharmony_ci pr_debug("Invalid primary paace entry\n"); 1098c2ecf20Sopenharmony_ci return -ENOENT; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (!get_bf(ppaace->addr_bitfields, PPAACE_AF_WSE)) { 1138c2ecf20Sopenharmony_ci pr_debug("liodn %d not configured\n", liodn); 1148c2ecf20Sopenharmony_ci return -EINVAL; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* Ensure that all other stores to the ppaace complete first */ 1188c2ecf20Sopenharmony_ci mb(); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci set_bf(ppaace->addr_bitfields, PAACE_AF_V, PAACE_V_VALID); 1218c2ecf20Sopenharmony_ci mb(); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return 0; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/** 1278c2ecf20Sopenharmony_ci * pamu_disable_liodn() - Clears valid bit of PACCE 1288c2ecf20Sopenharmony_ci * @liodn: liodn PAACT index for desired PAACE 1298c2ecf20Sopenharmony_ci * 1308c2ecf20Sopenharmony_ci * Returns 0 upon success else error code < 0 returned 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_ciint pamu_disable_liodn(int liodn) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci struct paace *ppaace; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci ppaace = pamu_get_ppaace(liodn); 1378c2ecf20Sopenharmony_ci if (!ppaace) { 1388c2ecf20Sopenharmony_ci pr_debug("Invalid primary paace entry\n"); 1398c2ecf20Sopenharmony_ci return -ENOENT; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci set_bf(ppaace->addr_bitfields, PAACE_AF_V, PAACE_V_INVALID); 1438c2ecf20Sopenharmony_ci mb(); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return 0; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci/* Derive the window size encoding for a particular PAACE entry */ 1498c2ecf20Sopenharmony_cistatic unsigned int map_addrspace_size_to_wse(phys_addr_t addrspace_size) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci /* Bug if not a power of 2 */ 1528c2ecf20Sopenharmony_ci BUG_ON(addrspace_size & (addrspace_size - 1)); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* window size is 2^(WSE+1) bytes */ 1558c2ecf20Sopenharmony_ci return fls64(addrspace_size) - 2; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci/* Derive the PAACE window count encoding for the subwindow count */ 1598c2ecf20Sopenharmony_cistatic unsigned int map_subwindow_cnt_to_wce(u32 subwindow_cnt) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci /* window count is 2^(WCE+1) bytes */ 1628c2ecf20Sopenharmony_ci return __ffs(subwindow_cnt) - 1; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* 1668c2ecf20Sopenharmony_ci * Set the PAACE type as primary and set the coherency required domain 1678c2ecf20Sopenharmony_ci * attribute 1688c2ecf20Sopenharmony_ci */ 1698c2ecf20Sopenharmony_cistatic void pamu_init_ppaace(struct paace *ppaace) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci set_bf(ppaace->addr_bitfields, PAACE_AF_PT, PAACE_PT_PRIMARY); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci set_bf(ppaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR, 1748c2ecf20Sopenharmony_ci PAACE_M_COHERENCE_REQ); 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci/* 1788c2ecf20Sopenharmony_ci * Set the PAACE type as secondary and set the coherency required domain 1798c2ecf20Sopenharmony_ci * attribute. 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_cistatic void pamu_init_spaace(struct paace *spaace) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci set_bf(spaace->addr_bitfields, PAACE_AF_PT, PAACE_PT_SECONDARY); 1848c2ecf20Sopenharmony_ci set_bf(spaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR, 1858c2ecf20Sopenharmony_ci PAACE_M_COHERENCE_REQ); 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci/* 1898c2ecf20Sopenharmony_ci * Return the spaace (corresponding to the secondary window index) 1908c2ecf20Sopenharmony_ci * for a particular ppaace. 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_cistatic struct paace *pamu_get_spaace(struct paace *paace, u32 wnum) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci u32 subwin_cnt; 1958c2ecf20Sopenharmony_ci struct paace *spaace = NULL; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci subwin_cnt = 1UL << (get_bf(paace->impl_attr, PAACE_IA_WCE) + 1); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (wnum < subwin_cnt) 2008c2ecf20Sopenharmony_ci spaace = &spaact[paace->fspi + wnum]; 2018c2ecf20Sopenharmony_ci else 2028c2ecf20Sopenharmony_ci pr_debug("secondary paace out of bounds\n"); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return spaace; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/** 2088c2ecf20Sopenharmony_ci * pamu_get_fspi_and_allocate() - Allocates fspi index and reserves subwindows 2098c2ecf20Sopenharmony_ci * required for primary PAACE in the secondary 2108c2ecf20Sopenharmony_ci * PAACE table. 2118c2ecf20Sopenharmony_ci * @subwin_cnt: Number of subwindows to be reserved. 2128c2ecf20Sopenharmony_ci * 2138c2ecf20Sopenharmony_ci * A PPAACE entry may have a number of associated subwindows. A subwindow 2148c2ecf20Sopenharmony_ci * corresponds to a SPAACE entry in the SPAACT table. Each PAACE entry stores 2158c2ecf20Sopenharmony_ci * the index (fspi) of the first SPAACE entry in the SPAACT table. This 2168c2ecf20Sopenharmony_ci * function returns the index of the first SPAACE entry. The remaining 2178c2ecf20Sopenharmony_ci * SPAACE entries are reserved contiguously from that index. 2188c2ecf20Sopenharmony_ci * 2198c2ecf20Sopenharmony_ci * Returns a valid fspi index in the range of 0 - SPAACE_NUMBER_ENTRIES on success. 2208c2ecf20Sopenharmony_ci * If no SPAACE entry is available or the allocator can not reserve the required 2218c2ecf20Sopenharmony_ci * number of contiguous entries function returns ULONG_MAX indicating a failure. 2228c2ecf20Sopenharmony_ci * 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_cistatic unsigned long pamu_get_fspi_and_allocate(u32 subwin_cnt) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci unsigned long spaace_addr; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci spaace_addr = gen_pool_alloc(spaace_pool, subwin_cnt * sizeof(struct paace)); 2298c2ecf20Sopenharmony_ci if (!spaace_addr) 2308c2ecf20Sopenharmony_ci return ULONG_MAX; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return (spaace_addr - (unsigned long)spaact) / (sizeof(struct paace)); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci/* Release the subwindows reserved for a particular LIODN */ 2368c2ecf20Sopenharmony_civoid pamu_free_subwins(int liodn) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct paace *ppaace; 2398c2ecf20Sopenharmony_ci u32 subwin_cnt, size; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci ppaace = pamu_get_ppaace(liodn); 2428c2ecf20Sopenharmony_ci if (!ppaace) { 2438c2ecf20Sopenharmony_ci pr_debug("Invalid liodn entry\n"); 2448c2ecf20Sopenharmony_ci return; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (get_bf(ppaace->addr_bitfields, PPAACE_AF_MW)) { 2488c2ecf20Sopenharmony_ci subwin_cnt = 1UL << (get_bf(ppaace->impl_attr, PAACE_IA_WCE) + 1); 2498c2ecf20Sopenharmony_ci size = (subwin_cnt - 1) * sizeof(struct paace); 2508c2ecf20Sopenharmony_ci gen_pool_free(spaace_pool, (unsigned long)&spaact[ppaace->fspi], size); 2518c2ecf20Sopenharmony_ci set_bf(ppaace->addr_bitfields, PPAACE_AF_MW, 0); 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci/* 2568c2ecf20Sopenharmony_ci * Function used for updating stash destination for the coressponding 2578c2ecf20Sopenharmony_ci * LIODN. 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_ciint pamu_update_paace_stash(int liodn, u32 subwin, u32 value) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct paace *paace; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci paace = pamu_get_ppaace(liodn); 2648c2ecf20Sopenharmony_ci if (!paace) { 2658c2ecf20Sopenharmony_ci pr_debug("Invalid liodn entry\n"); 2668c2ecf20Sopenharmony_ci return -ENOENT; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci if (subwin) { 2698c2ecf20Sopenharmony_ci paace = pamu_get_spaace(paace, subwin - 1); 2708c2ecf20Sopenharmony_ci if (!paace) 2718c2ecf20Sopenharmony_ci return -ENOENT; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci set_bf(paace->impl_attr, PAACE_IA_CID, value); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci mb(); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return 0; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci/* Disable a subwindow corresponding to the LIODN */ 2818c2ecf20Sopenharmony_ciint pamu_disable_spaace(int liodn, u32 subwin) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct paace *paace; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci paace = pamu_get_ppaace(liodn); 2868c2ecf20Sopenharmony_ci if (!paace) { 2878c2ecf20Sopenharmony_ci pr_debug("Invalid liodn entry\n"); 2888c2ecf20Sopenharmony_ci return -ENOENT; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci if (subwin) { 2918c2ecf20Sopenharmony_ci paace = pamu_get_spaace(paace, subwin - 1); 2928c2ecf20Sopenharmony_ci if (!paace) 2938c2ecf20Sopenharmony_ci return -ENOENT; 2948c2ecf20Sopenharmony_ci set_bf(paace->addr_bitfields, PAACE_AF_V, PAACE_V_INVALID); 2958c2ecf20Sopenharmony_ci } else { 2968c2ecf20Sopenharmony_ci set_bf(paace->addr_bitfields, PAACE_AF_AP, 2978c2ecf20Sopenharmony_ci PAACE_AP_PERMS_DENIED); 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci mb(); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/** 3068c2ecf20Sopenharmony_ci * pamu_config_paace() - Sets up PPAACE entry for specified liodn 3078c2ecf20Sopenharmony_ci * 3088c2ecf20Sopenharmony_ci * @liodn: Logical IO device number 3098c2ecf20Sopenharmony_ci * @win_addr: starting address of DSA window 3108c2ecf20Sopenharmony_ci * @win-size: size of DSA window 3118c2ecf20Sopenharmony_ci * @omi: Operation mapping index -- if ~omi == 0 then omi not defined 3128c2ecf20Sopenharmony_ci * @rpn: real (true physical) page number 3138c2ecf20Sopenharmony_ci * @stashid: cache stash id for associated cpu -- if ~stashid == 0 then 3148c2ecf20Sopenharmony_ci * stashid not defined 3158c2ecf20Sopenharmony_ci * @snoopid: snoop id for hardware coherency -- if ~snoopid == 0 then 3168c2ecf20Sopenharmony_ci * snoopid not defined 3178c2ecf20Sopenharmony_ci * @subwin_cnt: number of sub-windows 3188c2ecf20Sopenharmony_ci * @prot: window permissions 3198c2ecf20Sopenharmony_ci * 3208c2ecf20Sopenharmony_ci * Returns 0 upon success else error code < 0 returned 3218c2ecf20Sopenharmony_ci */ 3228c2ecf20Sopenharmony_ciint pamu_config_ppaace(int liodn, phys_addr_t win_addr, phys_addr_t win_size, 3238c2ecf20Sopenharmony_ci u32 omi, unsigned long rpn, u32 snoopid, u32 stashid, 3248c2ecf20Sopenharmony_ci u32 subwin_cnt, int prot) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci struct paace *ppaace; 3278c2ecf20Sopenharmony_ci unsigned long fspi; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if ((win_size & (win_size - 1)) || win_size < PAMU_PAGE_SIZE) { 3308c2ecf20Sopenharmony_ci pr_debug("window size too small or not a power of two %pa\n", 3318c2ecf20Sopenharmony_ci &win_size); 3328c2ecf20Sopenharmony_ci return -EINVAL; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (win_addr & (win_size - 1)) { 3368c2ecf20Sopenharmony_ci pr_debug("window address is not aligned with window size\n"); 3378c2ecf20Sopenharmony_ci return -EINVAL; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci ppaace = pamu_get_ppaace(liodn); 3418c2ecf20Sopenharmony_ci if (!ppaace) 3428c2ecf20Sopenharmony_ci return -ENOENT; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci /* window size is 2^(WSE+1) bytes */ 3458c2ecf20Sopenharmony_ci set_bf(ppaace->addr_bitfields, PPAACE_AF_WSE, 3468c2ecf20Sopenharmony_ci map_addrspace_size_to_wse(win_size)); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci pamu_init_ppaace(ppaace); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci ppaace->wbah = win_addr >> (PAMU_PAGE_SHIFT + 20); 3518c2ecf20Sopenharmony_ci set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL, 3528c2ecf20Sopenharmony_ci (win_addr >> PAMU_PAGE_SHIFT)); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* set up operation mapping if it's configured */ 3558c2ecf20Sopenharmony_ci if (omi < OME_NUMBER_ENTRIES) { 3568c2ecf20Sopenharmony_ci set_bf(ppaace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED); 3578c2ecf20Sopenharmony_ci ppaace->op_encode.index_ot.omi = omi; 3588c2ecf20Sopenharmony_ci } else if (~omi != 0) { 3598c2ecf20Sopenharmony_ci pr_debug("bad operation mapping index: %d\n", omi); 3608c2ecf20Sopenharmony_ci return -EINVAL; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* configure stash id */ 3648c2ecf20Sopenharmony_ci if (~stashid != 0) 3658c2ecf20Sopenharmony_ci set_bf(ppaace->impl_attr, PAACE_IA_CID, stashid); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* configure snoop id */ 3688c2ecf20Sopenharmony_ci if (~snoopid != 0) 3698c2ecf20Sopenharmony_ci ppaace->domain_attr.to_host.snpid = snoopid; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (subwin_cnt) { 3728c2ecf20Sopenharmony_ci /* The first entry is in the primary PAACE instead */ 3738c2ecf20Sopenharmony_ci fspi = pamu_get_fspi_and_allocate(subwin_cnt - 1); 3748c2ecf20Sopenharmony_ci if (fspi == ULONG_MAX) { 3758c2ecf20Sopenharmony_ci pr_debug("spaace indexes exhausted\n"); 3768c2ecf20Sopenharmony_ci return -EINVAL; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* window count is 2^(WCE+1) bytes */ 3808c2ecf20Sopenharmony_ci set_bf(ppaace->impl_attr, PAACE_IA_WCE, 3818c2ecf20Sopenharmony_ci map_subwindow_cnt_to_wce(subwin_cnt)); 3828c2ecf20Sopenharmony_ci set_bf(ppaace->addr_bitfields, PPAACE_AF_MW, 0x1); 3838c2ecf20Sopenharmony_ci ppaace->fspi = fspi; 3848c2ecf20Sopenharmony_ci } else { 3858c2ecf20Sopenharmony_ci set_bf(ppaace->impl_attr, PAACE_IA_ATM, PAACE_ATM_WINDOW_XLATE); 3868c2ecf20Sopenharmony_ci ppaace->twbah = rpn >> 20; 3878c2ecf20Sopenharmony_ci set_bf(ppaace->win_bitfields, PAACE_WIN_TWBAL, rpn); 3888c2ecf20Sopenharmony_ci set_bf(ppaace->addr_bitfields, PAACE_AF_AP, prot); 3898c2ecf20Sopenharmony_ci set_bf(ppaace->impl_attr, PAACE_IA_WCE, 0); 3908c2ecf20Sopenharmony_ci set_bf(ppaace->addr_bitfields, PPAACE_AF_MW, 0); 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci mb(); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci return 0; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci/** 3988c2ecf20Sopenharmony_ci * pamu_config_spaace() - Sets up SPAACE entry for specified subwindow 3998c2ecf20Sopenharmony_ci * 4008c2ecf20Sopenharmony_ci * @liodn: Logical IO device number 4018c2ecf20Sopenharmony_ci * @subwin_cnt: number of sub-windows associated with dma-window 4028c2ecf20Sopenharmony_ci * @subwin: subwindow index 4038c2ecf20Sopenharmony_ci * @subwin_size: size of subwindow 4048c2ecf20Sopenharmony_ci * @omi: Operation mapping index 4058c2ecf20Sopenharmony_ci * @rpn: real (true physical) page number 4068c2ecf20Sopenharmony_ci * @snoopid: snoop id for hardware coherency -- if ~snoopid == 0 then 4078c2ecf20Sopenharmony_ci * snoopid not defined 4088c2ecf20Sopenharmony_ci * @stashid: cache stash id for associated cpu 4098c2ecf20Sopenharmony_ci * @enable: enable/disable subwindow after reconfiguration 4108c2ecf20Sopenharmony_ci * @prot: sub window permissions 4118c2ecf20Sopenharmony_ci * 4128c2ecf20Sopenharmony_ci * Returns 0 upon success else error code < 0 returned 4138c2ecf20Sopenharmony_ci */ 4148c2ecf20Sopenharmony_ciint pamu_config_spaace(int liodn, u32 subwin_cnt, u32 subwin, 4158c2ecf20Sopenharmony_ci phys_addr_t subwin_size, u32 omi, unsigned long rpn, 4168c2ecf20Sopenharmony_ci u32 snoopid, u32 stashid, int enable, int prot) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct paace *paace; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci /* setup sub-windows */ 4218c2ecf20Sopenharmony_ci if (!subwin_cnt) { 4228c2ecf20Sopenharmony_ci pr_debug("Invalid subwindow count\n"); 4238c2ecf20Sopenharmony_ci return -EINVAL; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci paace = pamu_get_ppaace(liodn); 4278c2ecf20Sopenharmony_ci if (subwin > 0 && subwin < subwin_cnt && paace) { 4288c2ecf20Sopenharmony_ci paace = pamu_get_spaace(paace, subwin - 1); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (paace && !(paace->addr_bitfields & PAACE_V_VALID)) { 4318c2ecf20Sopenharmony_ci pamu_init_spaace(paace); 4328c2ecf20Sopenharmony_ci set_bf(paace->addr_bitfields, SPAACE_AF_LIODN, liodn); 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (!paace) { 4378c2ecf20Sopenharmony_ci pr_debug("Invalid liodn entry\n"); 4388c2ecf20Sopenharmony_ci return -ENOENT; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if ((subwin_size & (subwin_size - 1)) || subwin_size < PAMU_PAGE_SIZE) { 4428c2ecf20Sopenharmony_ci pr_debug("subwindow size out of range, or not a power of 2\n"); 4438c2ecf20Sopenharmony_ci return -EINVAL; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (rpn == ULONG_MAX) { 4478c2ecf20Sopenharmony_ci pr_debug("real page number out of range\n"); 4488c2ecf20Sopenharmony_ci return -EINVAL; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* window size is 2^(WSE+1) bytes */ 4528c2ecf20Sopenharmony_ci set_bf(paace->win_bitfields, PAACE_WIN_SWSE, 4538c2ecf20Sopenharmony_ci map_addrspace_size_to_wse(subwin_size)); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci set_bf(paace->impl_attr, PAACE_IA_ATM, PAACE_ATM_WINDOW_XLATE); 4568c2ecf20Sopenharmony_ci paace->twbah = rpn >> 20; 4578c2ecf20Sopenharmony_ci set_bf(paace->win_bitfields, PAACE_WIN_TWBAL, rpn); 4588c2ecf20Sopenharmony_ci set_bf(paace->addr_bitfields, PAACE_AF_AP, prot); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci /* configure snoop id */ 4618c2ecf20Sopenharmony_ci if (~snoopid != 0) 4628c2ecf20Sopenharmony_ci paace->domain_attr.to_host.snpid = snoopid; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* set up operation mapping if it's configured */ 4658c2ecf20Sopenharmony_ci if (omi < OME_NUMBER_ENTRIES) { 4668c2ecf20Sopenharmony_ci set_bf(paace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED); 4678c2ecf20Sopenharmony_ci paace->op_encode.index_ot.omi = omi; 4688c2ecf20Sopenharmony_ci } else if (~omi != 0) { 4698c2ecf20Sopenharmony_ci pr_debug("bad operation mapping index: %d\n", omi); 4708c2ecf20Sopenharmony_ci return -EINVAL; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (~stashid != 0) 4748c2ecf20Sopenharmony_ci set_bf(paace->impl_attr, PAACE_IA_CID, stashid); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci smp_wmb(); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (enable) 4798c2ecf20Sopenharmony_ci set_bf(paace->addr_bitfields, PAACE_AF_V, PAACE_V_VALID); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci mb(); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci return 0; 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci/** 4878c2ecf20Sopenharmony_ci * get_ome_index() - Returns the index in the operation mapping table 4888c2ecf20Sopenharmony_ci * for device. 4898c2ecf20Sopenharmony_ci * @*omi_index: pointer for storing the index value 4908c2ecf20Sopenharmony_ci * 4918c2ecf20Sopenharmony_ci */ 4928c2ecf20Sopenharmony_civoid get_ome_index(u32 *omi_index, struct device *dev) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci if (of_device_is_compatible(dev->of_node, "fsl,qman-portal")) 4958c2ecf20Sopenharmony_ci *omi_index = OMI_QMAN; 4968c2ecf20Sopenharmony_ci if (of_device_is_compatible(dev->of_node, "fsl,qman")) 4978c2ecf20Sopenharmony_ci *omi_index = OMI_QMAN_PRIV; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci/** 5018c2ecf20Sopenharmony_ci * get_stash_id - Returns stash destination id corresponding to a 5028c2ecf20Sopenharmony_ci * cache type and vcpu. 5038c2ecf20Sopenharmony_ci * @stash_dest_hint: L1, L2 or L3 5048c2ecf20Sopenharmony_ci * @vcpu: vpcu target for a particular cache type. 5058c2ecf20Sopenharmony_ci * 5068c2ecf20Sopenharmony_ci * Returs stash on success or ~(u32)0 on failure. 5078c2ecf20Sopenharmony_ci * 5088c2ecf20Sopenharmony_ci */ 5098c2ecf20Sopenharmony_ciu32 get_stash_id(u32 stash_dest_hint, u32 vcpu) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci const u32 *prop; 5128c2ecf20Sopenharmony_ci struct device_node *node; 5138c2ecf20Sopenharmony_ci u32 cache_level; 5148c2ecf20Sopenharmony_ci int len, found = 0; 5158c2ecf20Sopenharmony_ci int i; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* Fastpath, exit early if L3/CPC cache is target for stashing */ 5188c2ecf20Sopenharmony_ci if (stash_dest_hint == PAMU_ATTR_CACHE_L3) { 5198c2ecf20Sopenharmony_ci node = of_find_matching_node(NULL, l3_device_ids); 5208c2ecf20Sopenharmony_ci if (node) { 5218c2ecf20Sopenharmony_ci prop = of_get_property(node, "cache-stash-id", NULL); 5228c2ecf20Sopenharmony_ci if (!prop) { 5238c2ecf20Sopenharmony_ci pr_debug("missing cache-stash-id at %pOF\n", 5248c2ecf20Sopenharmony_ci node); 5258c2ecf20Sopenharmony_ci of_node_put(node); 5268c2ecf20Sopenharmony_ci return ~(u32)0; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci of_node_put(node); 5298c2ecf20Sopenharmony_ci return be32_to_cpup(prop); 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci return ~(u32)0; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci for_each_of_cpu_node(node) { 5358c2ecf20Sopenharmony_ci prop = of_get_property(node, "reg", &len); 5368c2ecf20Sopenharmony_ci for (i = 0; i < len / sizeof(u32); i++) { 5378c2ecf20Sopenharmony_ci if (be32_to_cpup(&prop[i]) == vcpu) { 5388c2ecf20Sopenharmony_ci found = 1; 5398c2ecf20Sopenharmony_ci goto found_cpu_node; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_cifound_cpu_node: 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci /* find the hwnode that represents the cache */ 5468c2ecf20Sopenharmony_ci for (cache_level = PAMU_ATTR_CACHE_L1; (cache_level < PAMU_ATTR_CACHE_L3) && found; cache_level++) { 5478c2ecf20Sopenharmony_ci if (stash_dest_hint == cache_level) { 5488c2ecf20Sopenharmony_ci prop = of_get_property(node, "cache-stash-id", NULL); 5498c2ecf20Sopenharmony_ci if (!prop) { 5508c2ecf20Sopenharmony_ci pr_debug("missing cache-stash-id at %pOF\n", 5518c2ecf20Sopenharmony_ci node); 5528c2ecf20Sopenharmony_ci of_node_put(node); 5538c2ecf20Sopenharmony_ci return ~(u32)0; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci of_node_put(node); 5568c2ecf20Sopenharmony_ci return be32_to_cpup(prop); 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci prop = of_get_property(node, "next-level-cache", NULL); 5608c2ecf20Sopenharmony_ci if (!prop) { 5618c2ecf20Sopenharmony_ci pr_debug("can't find next-level-cache at %pOF\n", node); 5628c2ecf20Sopenharmony_ci of_node_put(node); 5638c2ecf20Sopenharmony_ci return ~(u32)0; /* can't traverse any further */ 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci of_node_put(node); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* advance to next node in cache hierarchy */ 5688c2ecf20Sopenharmony_ci node = of_find_node_by_phandle(*prop); 5698c2ecf20Sopenharmony_ci if (!node) { 5708c2ecf20Sopenharmony_ci pr_debug("Invalid node for cache hierarchy\n"); 5718c2ecf20Sopenharmony_ci return ~(u32)0; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci pr_debug("stash dest not found for %d on vcpu %d\n", 5768c2ecf20Sopenharmony_ci stash_dest_hint, vcpu); 5778c2ecf20Sopenharmony_ci return ~(u32)0; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci/* Identify if the PAACT table entry belongs to QMAN, BMAN or QMAN Portal */ 5818c2ecf20Sopenharmony_ci#define QMAN_PAACE 1 5828c2ecf20Sopenharmony_ci#define QMAN_PORTAL_PAACE 2 5838c2ecf20Sopenharmony_ci#define BMAN_PAACE 3 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci/** 5868c2ecf20Sopenharmony_ci * Setup operation mapping and stash destinations for QMAN and QMAN portal. 5878c2ecf20Sopenharmony_ci * Memory accesses to QMAN and BMAN private memory need not be coherent, so 5888c2ecf20Sopenharmony_ci * clear the PAACE entry coherency attribute for them. 5898c2ecf20Sopenharmony_ci */ 5908c2ecf20Sopenharmony_cistatic void setup_qbman_paace(struct paace *ppaace, int paace_type) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci switch (paace_type) { 5938c2ecf20Sopenharmony_ci case QMAN_PAACE: 5948c2ecf20Sopenharmony_ci set_bf(ppaace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED); 5958c2ecf20Sopenharmony_ci ppaace->op_encode.index_ot.omi = OMI_QMAN_PRIV; 5968c2ecf20Sopenharmony_ci /* setup QMAN Private data stashing for the L3 cache */ 5978c2ecf20Sopenharmony_ci set_bf(ppaace->impl_attr, PAACE_IA_CID, get_stash_id(PAMU_ATTR_CACHE_L3, 0)); 5988c2ecf20Sopenharmony_ci set_bf(ppaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR, 5998c2ecf20Sopenharmony_ci 0); 6008c2ecf20Sopenharmony_ci break; 6018c2ecf20Sopenharmony_ci case QMAN_PORTAL_PAACE: 6028c2ecf20Sopenharmony_ci set_bf(ppaace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED); 6038c2ecf20Sopenharmony_ci ppaace->op_encode.index_ot.omi = OMI_QMAN; 6048c2ecf20Sopenharmony_ci /* Set DQRR and Frame stashing for the L3 cache */ 6058c2ecf20Sopenharmony_ci set_bf(ppaace->impl_attr, PAACE_IA_CID, get_stash_id(PAMU_ATTR_CACHE_L3, 0)); 6068c2ecf20Sopenharmony_ci break; 6078c2ecf20Sopenharmony_ci case BMAN_PAACE: 6088c2ecf20Sopenharmony_ci set_bf(ppaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR, 6098c2ecf20Sopenharmony_ci 0); 6108c2ecf20Sopenharmony_ci break; 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci/** 6158c2ecf20Sopenharmony_ci * Setup the operation mapping table for various devices. This is a static 6168c2ecf20Sopenharmony_ci * table where each table index corresponds to a particular device. PAMU uses 6178c2ecf20Sopenharmony_ci * this table to translate device transaction to appropriate corenet 6188c2ecf20Sopenharmony_ci * transaction. 6198c2ecf20Sopenharmony_ci */ 6208c2ecf20Sopenharmony_cistatic void setup_omt(struct ome *omt) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci struct ome *ome; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* Configure OMI_QMAN */ 6258c2ecf20Sopenharmony_ci ome = &omt[OMI_QMAN]; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci ome->moe[IOE_READ_IDX] = EOE_VALID | EOE_READ; 6288c2ecf20Sopenharmony_ci ome->moe[IOE_EREAD0_IDX] = EOE_VALID | EOE_RSA; 6298c2ecf20Sopenharmony_ci ome->moe[IOE_WRITE_IDX] = EOE_VALID | EOE_WRITE; 6308c2ecf20Sopenharmony_ci ome->moe[IOE_EWRITE0_IDX] = EOE_VALID | EOE_WWSAO; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci ome->moe[IOE_DIRECT0_IDX] = EOE_VALID | EOE_LDEC; 6338c2ecf20Sopenharmony_ci ome->moe[IOE_DIRECT1_IDX] = EOE_VALID | EOE_LDECPE; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci /* Configure OMI_FMAN */ 6368c2ecf20Sopenharmony_ci ome = &omt[OMI_FMAN]; 6378c2ecf20Sopenharmony_ci ome->moe[IOE_READ_IDX] = EOE_VALID | EOE_READI; 6388c2ecf20Sopenharmony_ci ome->moe[IOE_WRITE_IDX] = EOE_VALID | EOE_WRITE; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci /* Configure OMI_QMAN private */ 6418c2ecf20Sopenharmony_ci ome = &omt[OMI_QMAN_PRIV]; 6428c2ecf20Sopenharmony_ci ome->moe[IOE_READ_IDX] = EOE_VALID | EOE_READ; 6438c2ecf20Sopenharmony_ci ome->moe[IOE_WRITE_IDX] = EOE_VALID | EOE_WRITE; 6448c2ecf20Sopenharmony_ci ome->moe[IOE_EREAD0_IDX] = EOE_VALID | EOE_RSA; 6458c2ecf20Sopenharmony_ci ome->moe[IOE_EWRITE0_IDX] = EOE_VALID | EOE_WWSA; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* Configure OMI_CAAM */ 6488c2ecf20Sopenharmony_ci ome = &omt[OMI_CAAM]; 6498c2ecf20Sopenharmony_ci ome->moe[IOE_READ_IDX] = EOE_VALID | EOE_READI; 6508c2ecf20Sopenharmony_ci ome->moe[IOE_WRITE_IDX] = EOE_VALID | EOE_WRITE; 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci/* 6548c2ecf20Sopenharmony_ci * Get the maximum number of PAACT table entries 6558c2ecf20Sopenharmony_ci * and subwindows supported by PAMU 6568c2ecf20Sopenharmony_ci */ 6578c2ecf20Sopenharmony_cistatic void get_pamu_cap_values(unsigned long pamu_reg_base) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci u32 pc_val; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci pc_val = in_be32((u32 *)(pamu_reg_base + PAMU_PC3)); 6628c2ecf20Sopenharmony_ci /* Maximum number of subwindows per liodn */ 6638c2ecf20Sopenharmony_ci max_subwindow_count = 1 << (1 + PAMU_PC3_MWCE(pc_val)); 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci/* Setup PAMU registers pointing to PAACT, SPAACT and OMT */ 6678c2ecf20Sopenharmony_cistatic int setup_one_pamu(unsigned long pamu_reg_base, unsigned long pamu_reg_size, 6688c2ecf20Sopenharmony_ci phys_addr_t ppaact_phys, phys_addr_t spaact_phys, 6698c2ecf20Sopenharmony_ci phys_addr_t omt_phys) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci u32 *pc; 6728c2ecf20Sopenharmony_ci struct pamu_mmap_regs *pamu_regs; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci pc = (u32 *) (pamu_reg_base + PAMU_PC); 6758c2ecf20Sopenharmony_ci pamu_regs = (struct pamu_mmap_regs *) 6768c2ecf20Sopenharmony_ci (pamu_reg_base + PAMU_MMAP_REGS_BASE); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci /* set up pointers to corenet control blocks */ 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci out_be32(&pamu_regs->ppbah, upper_32_bits(ppaact_phys)); 6818c2ecf20Sopenharmony_ci out_be32(&pamu_regs->ppbal, lower_32_bits(ppaact_phys)); 6828c2ecf20Sopenharmony_ci ppaact_phys = ppaact_phys + PAACT_SIZE; 6838c2ecf20Sopenharmony_ci out_be32(&pamu_regs->pplah, upper_32_bits(ppaact_phys)); 6848c2ecf20Sopenharmony_ci out_be32(&pamu_regs->pplal, lower_32_bits(ppaact_phys)); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci out_be32(&pamu_regs->spbah, upper_32_bits(spaact_phys)); 6878c2ecf20Sopenharmony_ci out_be32(&pamu_regs->spbal, lower_32_bits(spaact_phys)); 6888c2ecf20Sopenharmony_ci spaact_phys = spaact_phys + SPAACT_SIZE; 6898c2ecf20Sopenharmony_ci out_be32(&pamu_regs->splah, upper_32_bits(spaact_phys)); 6908c2ecf20Sopenharmony_ci out_be32(&pamu_regs->splal, lower_32_bits(spaact_phys)); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci out_be32(&pamu_regs->obah, upper_32_bits(omt_phys)); 6938c2ecf20Sopenharmony_ci out_be32(&pamu_regs->obal, lower_32_bits(omt_phys)); 6948c2ecf20Sopenharmony_ci omt_phys = omt_phys + OMT_SIZE; 6958c2ecf20Sopenharmony_ci out_be32(&pamu_regs->olah, upper_32_bits(omt_phys)); 6968c2ecf20Sopenharmony_ci out_be32(&pamu_regs->olal, lower_32_bits(omt_phys)); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci /* 6998c2ecf20Sopenharmony_ci * set PAMU enable bit, 7008c2ecf20Sopenharmony_ci * allow ppaact & omt to be cached 7018c2ecf20Sopenharmony_ci * & enable PAMU access violation interrupts. 7028c2ecf20Sopenharmony_ci */ 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci out_be32((u32 *)(pamu_reg_base + PAMU_PICS), 7058c2ecf20Sopenharmony_ci PAMU_ACCESS_VIOLATION_ENABLE); 7068c2ecf20Sopenharmony_ci out_be32(pc, PAMU_PC_PE | PAMU_PC_OCE | PAMU_PC_SPCC | PAMU_PC_PPCC); 7078c2ecf20Sopenharmony_ci return 0; 7088c2ecf20Sopenharmony_ci} 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci/* Enable all device LIODNS */ 7118c2ecf20Sopenharmony_cistatic void setup_liodns(void) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci int i, len; 7148c2ecf20Sopenharmony_ci struct paace *ppaace; 7158c2ecf20Sopenharmony_ci struct device_node *node = NULL; 7168c2ecf20Sopenharmony_ci const u32 *prop; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci for_each_node_with_property(node, "fsl,liodn") { 7198c2ecf20Sopenharmony_ci prop = of_get_property(node, "fsl,liodn", &len); 7208c2ecf20Sopenharmony_ci for (i = 0; i < len / sizeof(u32); i++) { 7218c2ecf20Sopenharmony_ci int liodn; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci liodn = be32_to_cpup(&prop[i]); 7248c2ecf20Sopenharmony_ci if (liodn >= PAACE_NUMBER_ENTRIES) { 7258c2ecf20Sopenharmony_ci pr_debug("Invalid LIODN value %d\n", liodn); 7268c2ecf20Sopenharmony_ci continue; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci ppaace = pamu_get_ppaace(liodn); 7298c2ecf20Sopenharmony_ci pamu_init_ppaace(ppaace); 7308c2ecf20Sopenharmony_ci /* window size is 2^(WSE+1) bytes */ 7318c2ecf20Sopenharmony_ci set_bf(ppaace->addr_bitfields, PPAACE_AF_WSE, 35); 7328c2ecf20Sopenharmony_ci ppaace->wbah = 0; 7338c2ecf20Sopenharmony_ci set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL, 0); 7348c2ecf20Sopenharmony_ci set_bf(ppaace->impl_attr, PAACE_IA_ATM, 7358c2ecf20Sopenharmony_ci PAACE_ATM_NO_XLATE); 7368c2ecf20Sopenharmony_ci set_bf(ppaace->addr_bitfields, PAACE_AF_AP, 7378c2ecf20Sopenharmony_ci PAACE_AP_PERMS_ALL); 7388c2ecf20Sopenharmony_ci if (of_device_is_compatible(node, "fsl,qman-portal")) 7398c2ecf20Sopenharmony_ci setup_qbman_paace(ppaace, QMAN_PORTAL_PAACE); 7408c2ecf20Sopenharmony_ci if (of_device_is_compatible(node, "fsl,qman")) 7418c2ecf20Sopenharmony_ci setup_qbman_paace(ppaace, QMAN_PAACE); 7428c2ecf20Sopenharmony_ci if (of_device_is_compatible(node, "fsl,bman")) 7438c2ecf20Sopenharmony_ci setup_qbman_paace(ppaace, BMAN_PAACE); 7448c2ecf20Sopenharmony_ci mb(); 7458c2ecf20Sopenharmony_ci pamu_enable_liodn(liodn); 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_cistatic irqreturn_t pamu_av_isr(int irq, void *arg) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci struct pamu_isr_data *data = arg; 7538c2ecf20Sopenharmony_ci phys_addr_t phys; 7548c2ecf20Sopenharmony_ci unsigned int i, j, ret; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci pr_emerg("access violation interrupt\n"); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci for (i = 0; i < data->count; i++) { 7598c2ecf20Sopenharmony_ci void __iomem *p = data->pamu_reg_base + i * PAMU_OFFSET; 7608c2ecf20Sopenharmony_ci u32 pics = in_be32(p + PAMU_PICS); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (pics & PAMU_ACCESS_VIOLATION_STAT) { 7638c2ecf20Sopenharmony_ci u32 avs1 = in_be32(p + PAMU_AVS1); 7648c2ecf20Sopenharmony_ci struct paace *paace; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci pr_emerg("POES1=%08x\n", in_be32(p + PAMU_POES1)); 7678c2ecf20Sopenharmony_ci pr_emerg("POES2=%08x\n", in_be32(p + PAMU_POES2)); 7688c2ecf20Sopenharmony_ci pr_emerg("AVS1=%08x\n", avs1); 7698c2ecf20Sopenharmony_ci pr_emerg("AVS2=%08x\n", in_be32(p + PAMU_AVS2)); 7708c2ecf20Sopenharmony_ci pr_emerg("AVA=%016llx\n", 7718c2ecf20Sopenharmony_ci make64(in_be32(p + PAMU_AVAH), 7728c2ecf20Sopenharmony_ci in_be32(p + PAMU_AVAL))); 7738c2ecf20Sopenharmony_ci pr_emerg("UDAD=%08x\n", in_be32(p + PAMU_UDAD)); 7748c2ecf20Sopenharmony_ci pr_emerg("POEA=%016llx\n", 7758c2ecf20Sopenharmony_ci make64(in_be32(p + PAMU_POEAH), 7768c2ecf20Sopenharmony_ci in_be32(p + PAMU_POEAL))); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci phys = make64(in_be32(p + PAMU_POEAH), 7798c2ecf20Sopenharmony_ci in_be32(p + PAMU_POEAL)); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci /* Assume that POEA points to a PAACE */ 7828c2ecf20Sopenharmony_ci if (phys) { 7838c2ecf20Sopenharmony_ci u32 *paace = phys_to_virt(phys); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci /* Only the first four words are relevant */ 7868c2ecf20Sopenharmony_ci for (j = 0; j < 4; j++) 7878c2ecf20Sopenharmony_ci pr_emerg("PAACE[%u]=%08x\n", 7888c2ecf20Sopenharmony_ci j, in_be32(paace + j)); 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci /* clear access violation condition */ 7928c2ecf20Sopenharmony_ci out_be32(p + PAMU_AVS1, avs1 & PAMU_AV_MASK); 7938c2ecf20Sopenharmony_ci paace = pamu_get_ppaace(avs1 >> PAMU_AVS1_LIODN_SHIFT); 7948c2ecf20Sopenharmony_ci BUG_ON(!paace); 7958c2ecf20Sopenharmony_ci /* check if we got a violation for a disabled LIODN */ 7968c2ecf20Sopenharmony_ci if (!get_bf(paace->addr_bitfields, PAACE_AF_V)) { 7978c2ecf20Sopenharmony_ci /* 7988c2ecf20Sopenharmony_ci * As per hardware erratum A-003638, access 7998c2ecf20Sopenharmony_ci * violation can be reported for a disabled 8008c2ecf20Sopenharmony_ci * LIODN. If we hit that condition, disable 8018c2ecf20Sopenharmony_ci * access violation reporting. 8028c2ecf20Sopenharmony_ci */ 8038c2ecf20Sopenharmony_ci pics &= ~PAMU_ACCESS_VIOLATION_ENABLE; 8048c2ecf20Sopenharmony_ci } else { 8058c2ecf20Sopenharmony_ci /* Disable the LIODN */ 8068c2ecf20Sopenharmony_ci ret = pamu_disable_liodn(avs1 >> PAMU_AVS1_LIODN_SHIFT); 8078c2ecf20Sopenharmony_ci BUG_ON(ret); 8088c2ecf20Sopenharmony_ci pr_emerg("Disabling liodn %x\n", 8098c2ecf20Sopenharmony_ci avs1 >> PAMU_AVS1_LIODN_SHIFT); 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci out_be32((p + PAMU_PICS), pics); 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci return IRQ_HANDLED; 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci#define LAWAR_EN 0x80000000 8198c2ecf20Sopenharmony_ci#define LAWAR_TARGET_MASK 0x0FF00000 8208c2ecf20Sopenharmony_ci#define LAWAR_TARGET_SHIFT 20 8218c2ecf20Sopenharmony_ci#define LAWAR_SIZE_MASK 0x0000003F 8228c2ecf20Sopenharmony_ci#define LAWAR_CSDID_MASK 0x000FF000 8238c2ecf20Sopenharmony_ci#define LAWAR_CSDID_SHIFT 12 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci#define LAW_SIZE_4K 0xb 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_cistruct ccsr_law { 8288c2ecf20Sopenharmony_ci u32 lawbarh; /* LAWn base address high */ 8298c2ecf20Sopenharmony_ci u32 lawbarl; /* LAWn base address low */ 8308c2ecf20Sopenharmony_ci u32 lawar; /* LAWn attributes */ 8318c2ecf20Sopenharmony_ci u32 reserved; 8328c2ecf20Sopenharmony_ci}; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci/* 8358c2ecf20Sopenharmony_ci * Create a coherence subdomain for a given memory block. 8368c2ecf20Sopenharmony_ci */ 8378c2ecf20Sopenharmony_cistatic int create_csd(phys_addr_t phys, size_t size, u32 csd_port_id) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci struct device_node *np; 8408c2ecf20Sopenharmony_ci const __be32 *iprop; 8418c2ecf20Sopenharmony_ci void __iomem *lac = NULL; /* Local Access Control registers */ 8428c2ecf20Sopenharmony_ci struct ccsr_law __iomem *law; 8438c2ecf20Sopenharmony_ci void __iomem *ccm = NULL; 8448c2ecf20Sopenharmony_ci u32 __iomem *csdids; 8458c2ecf20Sopenharmony_ci unsigned int i, num_laws, num_csds; 8468c2ecf20Sopenharmony_ci u32 law_target = 0; 8478c2ecf20Sopenharmony_ci u32 csd_id = 0; 8488c2ecf20Sopenharmony_ci int ret = 0; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "fsl,corenet-law"); 8518c2ecf20Sopenharmony_ci if (!np) 8528c2ecf20Sopenharmony_ci return -ENODEV; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci iprop = of_get_property(np, "fsl,num-laws", NULL); 8558c2ecf20Sopenharmony_ci if (!iprop) { 8568c2ecf20Sopenharmony_ci ret = -ENODEV; 8578c2ecf20Sopenharmony_ci goto error; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci num_laws = be32_to_cpup(iprop); 8618c2ecf20Sopenharmony_ci if (!num_laws) { 8628c2ecf20Sopenharmony_ci ret = -ENODEV; 8638c2ecf20Sopenharmony_ci goto error; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci lac = of_iomap(np, 0); 8678c2ecf20Sopenharmony_ci if (!lac) { 8688c2ecf20Sopenharmony_ci ret = -ENODEV; 8698c2ecf20Sopenharmony_ci goto error; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci /* LAW registers are at offset 0xC00 */ 8738c2ecf20Sopenharmony_ci law = lac + 0xC00; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci of_node_put(np); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "fsl,corenet-cf"); 8788c2ecf20Sopenharmony_ci if (!np) { 8798c2ecf20Sopenharmony_ci ret = -ENODEV; 8808c2ecf20Sopenharmony_ci goto error; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci iprop = of_get_property(np, "fsl,ccf-num-csdids", NULL); 8848c2ecf20Sopenharmony_ci if (!iprop) { 8858c2ecf20Sopenharmony_ci ret = -ENODEV; 8868c2ecf20Sopenharmony_ci goto error; 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci num_csds = be32_to_cpup(iprop); 8908c2ecf20Sopenharmony_ci if (!num_csds) { 8918c2ecf20Sopenharmony_ci ret = -ENODEV; 8928c2ecf20Sopenharmony_ci goto error; 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci ccm = of_iomap(np, 0); 8968c2ecf20Sopenharmony_ci if (!ccm) { 8978c2ecf20Sopenharmony_ci ret = -ENOMEM; 8988c2ecf20Sopenharmony_ci goto error; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci /* The undocumented CSDID registers are at offset 0x600 */ 9028c2ecf20Sopenharmony_ci csdids = ccm + 0x600; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci of_node_put(np); 9058c2ecf20Sopenharmony_ci np = NULL; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci /* Find an unused coherence subdomain ID */ 9088c2ecf20Sopenharmony_ci for (csd_id = 0; csd_id < num_csds; csd_id++) { 9098c2ecf20Sopenharmony_ci if (!csdids[csd_id]) 9108c2ecf20Sopenharmony_ci break; 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* Store the Port ID in the (undocumented) proper CIDMRxx register */ 9148c2ecf20Sopenharmony_ci csdids[csd_id] = csd_port_id; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci /* Find the DDR LAW that maps to our buffer. */ 9178c2ecf20Sopenharmony_ci for (i = 0; i < num_laws; i++) { 9188c2ecf20Sopenharmony_ci if (law[i].lawar & LAWAR_EN) { 9198c2ecf20Sopenharmony_ci phys_addr_t law_start, law_end; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci law_start = make64(law[i].lawbarh, law[i].lawbarl); 9228c2ecf20Sopenharmony_ci law_end = law_start + 9238c2ecf20Sopenharmony_ci (2ULL << (law[i].lawar & LAWAR_SIZE_MASK)); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci if (law_start <= phys && phys < law_end) { 9268c2ecf20Sopenharmony_ci law_target = law[i].lawar & LAWAR_TARGET_MASK; 9278c2ecf20Sopenharmony_ci break; 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci if (i == 0 || i == num_laws) { 9338c2ecf20Sopenharmony_ci /* This should never happen */ 9348c2ecf20Sopenharmony_ci ret = -ENOENT; 9358c2ecf20Sopenharmony_ci goto error; 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci /* Find a free LAW entry */ 9398c2ecf20Sopenharmony_ci while (law[--i].lawar & LAWAR_EN) { 9408c2ecf20Sopenharmony_ci if (i == 0) { 9418c2ecf20Sopenharmony_ci /* No higher priority LAW slots available */ 9428c2ecf20Sopenharmony_ci ret = -ENOENT; 9438c2ecf20Sopenharmony_ci goto error; 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci law[i].lawbarh = upper_32_bits(phys); 9488c2ecf20Sopenharmony_ci law[i].lawbarl = lower_32_bits(phys); 9498c2ecf20Sopenharmony_ci wmb(); 9508c2ecf20Sopenharmony_ci law[i].lawar = LAWAR_EN | law_target | (csd_id << LAWAR_CSDID_SHIFT) | 9518c2ecf20Sopenharmony_ci (LAW_SIZE_4K + get_order(size)); 9528c2ecf20Sopenharmony_ci wmb(); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_cierror: 9558c2ecf20Sopenharmony_ci if (ccm) 9568c2ecf20Sopenharmony_ci iounmap(ccm); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci if (lac) 9598c2ecf20Sopenharmony_ci iounmap(lac); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (np) 9628c2ecf20Sopenharmony_ci of_node_put(np); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci return ret; 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci/* 9688c2ecf20Sopenharmony_ci * Table of SVRs and the corresponding PORT_ID values. Port ID corresponds to a 9698c2ecf20Sopenharmony_ci * bit map of snoopers for a given range of memory mapped by a LAW. 9708c2ecf20Sopenharmony_ci * 9718c2ecf20Sopenharmony_ci * All future CoreNet-enabled SOCs will have this erratum(A-004510) fixed, so this 9728c2ecf20Sopenharmony_ci * table should never need to be updated. SVRs are guaranteed to be unique, so 9738c2ecf20Sopenharmony_ci * there is no worry that a future SOC will inadvertently have one of these 9748c2ecf20Sopenharmony_ci * values. 9758c2ecf20Sopenharmony_ci */ 9768c2ecf20Sopenharmony_cistatic const struct { 9778c2ecf20Sopenharmony_ci u32 svr; 9788c2ecf20Sopenharmony_ci u32 port_id; 9798c2ecf20Sopenharmony_ci} port_id_map[] = { 9808c2ecf20Sopenharmony_ci {(SVR_P2040 << 8) | 0x10, 0xFF000000}, /* P2040 1.0 */ 9818c2ecf20Sopenharmony_ci {(SVR_P2040 << 8) | 0x11, 0xFF000000}, /* P2040 1.1 */ 9828c2ecf20Sopenharmony_ci {(SVR_P2041 << 8) | 0x10, 0xFF000000}, /* P2041 1.0 */ 9838c2ecf20Sopenharmony_ci {(SVR_P2041 << 8) | 0x11, 0xFF000000}, /* P2041 1.1 */ 9848c2ecf20Sopenharmony_ci {(SVR_P3041 << 8) | 0x10, 0xFF000000}, /* P3041 1.0 */ 9858c2ecf20Sopenharmony_ci {(SVR_P3041 << 8) | 0x11, 0xFF000000}, /* P3041 1.1 */ 9868c2ecf20Sopenharmony_ci {(SVR_P4040 << 8) | 0x20, 0xFFF80000}, /* P4040 2.0 */ 9878c2ecf20Sopenharmony_ci {(SVR_P4080 << 8) | 0x20, 0xFFF80000}, /* P4080 2.0 */ 9888c2ecf20Sopenharmony_ci {(SVR_P5010 << 8) | 0x10, 0xFC000000}, /* P5010 1.0 */ 9898c2ecf20Sopenharmony_ci {(SVR_P5010 << 8) | 0x20, 0xFC000000}, /* P5010 2.0 */ 9908c2ecf20Sopenharmony_ci {(SVR_P5020 << 8) | 0x10, 0xFC000000}, /* P5020 1.0 */ 9918c2ecf20Sopenharmony_ci {(SVR_P5021 << 8) | 0x10, 0xFF800000}, /* P5021 1.0 */ 9928c2ecf20Sopenharmony_ci {(SVR_P5040 << 8) | 0x10, 0xFF800000}, /* P5040 1.0 */ 9938c2ecf20Sopenharmony_ci}; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci#define SVR_SECURITY 0x80000 /* The Security (E) bit */ 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_cistatic int fsl_pamu_probe(struct platform_device *pdev) 9988c2ecf20Sopenharmony_ci{ 9998c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 10008c2ecf20Sopenharmony_ci void __iomem *pamu_regs = NULL; 10018c2ecf20Sopenharmony_ci struct ccsr_guts __iomem *guts_regs = NULL; 10028c2ecf20Sopenharmony_ci u32 pamubypenr, pamu_counter; 10038c2ecf20Sopenharmony_ci unsigned long pamu_reg_off; 10048c2ecf20Sopenharmony_ci unsigned long pamu_reg_base; 10058c2ecf20Sopenharmony_ci struct pamu_isr_data *data = NULL; 10068c2ecf20Sopenharmony_ci struct device_node *guts_node; 10078c2ecf20Sopenharmony_ci u64 size; 10088c2ecf20Sopenharmony_ci struct page *p; 10098c2ecf20Sopenharmony_ci int ret = 0; 10108c2ecf20Sopenharmony_ci int irq; 10118c2ecf20Sopenharmony_ci phys_addr_t ppaact_phys; 10128c2ecf20Sopenharmony_ci phys_addr_t spaact_phys; 10138c2ecf20Sopenharmony_ci struct ome *omt; 10148c2ecf20Sopenharmony_ci phys_addr_t omt_phys; 10158c2ecf20Sopenharmony_ci size_t mem_size = 0; 10168c2ecf20Sopenharmony_ci unsigned int order = 0; 10178c2ecf20Sopenharmony_ci u32 csd_port_id = 0; 10188c2ecf20Sopenharmony_ci unsigned i; 10198c2ecf20Sopenharmony_ci /* 10208c2ecf20Sopenharmony_ci * enumerate all PAMUs and allocate and setup PAMU tables 10218c2ecf20Sopenharmony_ci * for each of them, 10228c2ecf20Sopenharmony_ci * NOTE : All PAMUs share the same LIODN tables. 10238c2ecf20Sopenharmony_ci */ 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci if (WARN_ON(probed)) 10268c2ecf20Sopenharmony_ci return -EBUSY; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci pamu_regs = of_iomap(dev->of_node, 0); 10298c2ecf20Sopenharmony_ci if (!pamu_regs) { 10308c2ecf20Sopenharmony_ci dev_err(dev, "ioremap of PAMU node failed\n"); 10318c2ecf20Sopenharmony_ci return -ENOMEM; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci of_get_address(dev->of_node, 0, &size, NULL); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci irq = irq_of_parse_and_map(dev->of_node, 0); 10368c2ecf20Sopenharmony_ci if (irq == NO_IRQ) { 10378c2ecf20Sopenharmony_ci dev_warn(dev, "no interrupts listed in PAMU node\n"); 10388c2ecf20Sopenharmony_ci goto error; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci data = kzalloc(sizeof(*data), GFP_KERNEL); 10428c2ecf20Sopenharmony_ci if (!data) { 10438c2ecf20Sopenharmony_ci ret = -ENOMEM; 10448c2ecf20Sopenharmony_ci goto error; 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci data->pamu_reg_base = pamu_regs; 10478c2ecf20Sopenharmony_ci data->count = size / PAMU_OFFSET; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci /* The ISR needs access to the regs, so we won't iounmap them */ 10508c2ecf20Sopenharmony_ci ret = request_irq(irq, pamu_av_isr, 0, "pamu", data); 10518c2ecf20Sopenharmony_ci if (ret < 0) { 10528c2ecf20Sopenharmony_ci dev_err(dev, "error %i installing ISR for irq %i\n", ret, irq); 10538c2ecf20Sopenharmony_ci goto error; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci guts_node = of_find_matching_node(NULL, guts_device_ids); 10578c2ecf20Sopenharmony_ci if (!guts_node) { 10588c2ecf20Sopenharmony_ci dev_err(dev, "could not find GUTS node %pOF\n", dev->of_node); 10598c2ecf20Sopenharmony_ci ret = -ENODEV; 10608c2ecf20Sopenharmony_ci goto error; 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci guts_regs = of_iomap(guts_node, 0); 10648c2ecf20Sopenharmony_ci of_node_put(guts_node); 10658c2ecf20Sopenharmony_ci if (!guts_regs) { 10668c2ecf20Sopenharmony_ci dev_err(dev, "ioremap of GUTS node failed\n"); 10678c2ecf20Sopenharmony_ci ret = -ENODEV; 10688c2ecf20Sopenharmony_ci goto error; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci /* read in the PAMU capability registers */ 10728c2ecf20Sopenharmony_ci get_pamu_cap_values((unsigned long)pamu_regs); 10738c2ecf20Sopenharmony_ci /* 10748c2ecf20Sopenharmony_ci * To simplify the allocation of a coherency domain, we allocate the 10758c2ecf20Sopenharmony_ci * PAACT and the OMT in the same memory buffer. Unfortunately, this 10768c2ecf20Sopenharmony_ci * wastes more memory compared to allocating the buffers separately. 10778c2ecf20Sopenharmony_ci */ 10788c2ecf20Sopenharmony_ci /* Determine how much memory we need */ 10798c2ecf20Sopenharmony_ci mem_size = (PAGE_SIZE << get_order(PAACT_SIZE)) + 10808c2ecf20Sopenharmony_ci (PAGE_SIZE << get_order(SPAACT_SIZE)) + 10818c2ecf20Sopenharmony_ci (PAGE_SIZE << get_order(OMT_SIZE)); 10828c2ecf20Sopenharmony_ci order = get_order(mem_size); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci p = alloc_pages(GFP_KERNEL | __GFP_ZERO, order); 10858c2ecf20Sopenharmony_ci if (!p) { 10868c2ecf20Sopenharmony_ci dev_err(dev, "unable to allocate PAACT/SPAACT/OMT block\n"); 10878c2ecf20Sopenharmony_ci ret = -ENOMEM; 10888c2ecf20Sopenharmony_ci goto error; 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci ppaact = page_address(p); 10928c2ecf20Sopenharmony_ci ppaact_phys = page_to_phys(p); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci /* Make sure the memory is naturally aligned */ 10958c2ecf20Sopenharmony_ci if (ppaact_phys & ((PAGE_SIZE << order) - 1)) { 10968c2ecf20Sopenharmony_ci dev_err(dev, "PAACT/OMT block is unaligned\n"); 10978c2ecf20Sopenharmony_ci ret = -ENOMEM; 10988c2ecf20Sopenharmony_ci goto error; 10998c2ecf20Sopenharmony_ci } 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci spaact = (void *)ppaact + (PAGE_SIZE << get_order(PAACT_SIZE)); 11028c2ecf20Sopenharmony_ci omt = (void *)spaact + (PAGE_SIZE << get_order(SPAACT_SIZE)); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci dev_dbg(dev, "ppaact virt=%p phys=%pa\n", ppaact, &ppaact_phys); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci /* Check to see if we need to implement the work-around on this SOC */ 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci /* Determine the Port ID for our coherence subdomain */ 11098c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(port_id_map); i++) { 11108c2ecf20Sopenharmony_ci if (port_id_map[i].svr == (mfspr(SPRN_SVR) & ~SVR_SECURITY)) { 11118c2ecf20Sopenharmony_ci csd_port_id = port_id_map[i].port_id; 11128c2ecf20Sopenharmony_ci dev_dbg(dev, "found matching SVR %08x\n", 11138c2ecf20Sopenharmony_ci port_id_map[i].svr); 11148c2ecf20Sopenharmony_ci break; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci if (csd_port_id) { 11198c2ecf20Sopenharmony_ci dev_dbg(dev, "creating coherency subdomain at address %pa, size %zu, port id 0x%08x", 11208c2ecf20Sopenharmony_ci &ppaact_phys, mem_size, csd_port_id); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci ret = create_csd(ppaact_phys, mem_size, csd_port_id); 11238c2ecf20Sopenharmony_ci if (ret) { 11248c2ecf20Sopenharmony_ci dev_err(dev, "could not create coherence subdomain\n"); 11258c2ecf20Sopenharmony_ci goto error; 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci spaact_phys = virt_to_phys(spaact); 11308c2ecf20Sopenharmony_ci omt_phys = virt_to_phys(omt); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci spaace_pool = gen_pool_create(ilog2(sizeof(struct paace)), -1); 11338c2ecf20Sopenharmony_ci if (!spaace_pool) { 11348c2ecf20Sopenharmony_ci ret = -ENOMEM; 11358c2ecf20Sopenharmony_ci dev_err(dev, "Failed to allocate spaace gen pool\n"); 11368c2ecf20Sopenharmony_ci goto error; 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci ret = gen_pool_add(spaace_pool, (unsigned long)spaact, SPAACT_SIZE, -1); 11408c2ecf20Sopenharmony_ci if (ret) 11418c2ecf20Sopenharmony_ci goto error_genpool; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci pamubypenr = in_be32(&guts_regs->pamubypenr); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci for (pamu_reg_off = 0, pamu_counter = 0x80000000; pamu_reg_off < size; 11468c2ecf20Sopenharmony_ci pamu_reg_off += PAMU_OFFSET, pamu_counter >>= 1) { 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci pamu_reg_base = (unsigned long)pamu_regs + pamu_reg_off; 11498c2ecf20Sopenharmony_ci setup_one_pamu(pamu_reg_base, pamu_reg_off, ppaact_phys, 11508c2ecf20Sopenharmony_ci spaact_phys, omt_phys); 11518c2ecf20Sopenharmony_ci /* Disable PAMU bypass for this PAMU */ 11528c2ecf20Sopenharmony_ci pamubypenr &= ~pamu_counter; 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci setup_omt(omt); 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci /* Enable all relevant PAMU(s) */ 11588c2ecf20Sopenharmony_ci out_be32(&guts_regs->pamubypenr, pamubypenr); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci iounmap(guts_regs); 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci /* Enable DMA for the LIODNs in the device tree */ 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci setup_liodns(); 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci probed = true; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci return 0; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cierror_genpool: 11718c2ecf20Sopenharmony_ci gen_pool_destroy(spaace_pool); 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_cierror: 11748c2ecf20Sopenharmony_ci if (irq != NO_IRQ) 11758c2ecf20Sopenharmony_ci free_irq(irq, data); 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci kfree_sensitive(data); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci if (pamu_regs) 11808c2ecf20Sopenharmony_ci iounmap(pamu_regs); 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci if (guts_regs) 11838c2ecf20Sopenharmony_ci iounmap(guts_regs); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci if (ppaact) 11868c2ecf20Sopenharmony_ci free_pages((unsigned long)ppaact, order); 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci ppaact = NULL; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci return ret; 11918c2ecf20Sopenharmony_ci} 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_cistatic struct platform_driver fsl_of_pamu_driver = { 11948c2ecf20Sopenharmony_ci .driver = { 11958c2ecf20Sopenharmony_ci .name = "fsl-of-pamu", 11968c2ecf20Sopenharmony_ci }, 11978c2ecf20Sopenharmony_ci .probe = fsl_pamu_probe, 11988c2ecf20Sopenharmony_ci}; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_cistatic __init int fsl_pamu_init(void) 12018c2ecf20Sopenharmony_ci{ 12028c2ecf20Sopenharmony_ci struct platform_device *pdev = NULL; 12038c2ecf20Sopenharmony_ci struct device_node *np; 12048c2ecf20Sopenharmony_ci int ret; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci /* 12078c2ecf20Sopenharmony_ci * The normal OF process calls the probe function at some 12088c2ecf20Sopenharmony_ci * indeterminate later time, after most drivers have loaded. This is 12098c2ecf20Sopenharmony_ci * too late for us, because PAMU clients (like the Qman driver) 12108c2ecf20Sopenharmony_ci * depend on PAMU being initialized early. 12118c2ecf20Sopenharmony_ci * 12128c2ecf20Sopenharmony_ci * So instead, we "manually" call our probe function by creating the 12138c2ecf20Sopenharmony_ci * platform devices ourselves. 12148c2ecf20Sopenharmony_ci */ 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci /* 12178c2ecf20Sopenharmony_ci * We assume that there is only one PAMU node in the device tree. A 12188c2ecf20Sopenharmony_ci * single PAMU node represents all of the PAMU devices in the SOC 12198c2ecf20Sopenharmony_ci * already. Everything else already makes that assumption, and the 12208c2ecf20Sopenharmony_ci * binding for the PAMU nodes doesn't allow for any parent-child 12218c2ecf20Sopenharmony_ci * relationships anyway. In other words, support for more than one 12228c2ecf20Sopenharmony_ci * PAMU node would require significant changes to a lot of code. 12238c2ecf20Sopenharmony_ci */ 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "fsl,pamu"); 12268c2ecf20Sopenharmony_ci if (!np) { 12278c2ecf20Sopenharmony_ci pr_err("could not find a PAMU node\n"); 12288c2ecf20Sopenharmony_ci return -ENODEV; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci ret = platform_driver_register(&fsl_of_pamu_driver); 12328c2ecf20Sopenharmony_ci if (ret) { 12338c2ecf20Sopenharmony_ci pr_err("could not register driver (err=%i)\n", ret); 12348c2ecf20Sopenharmony_ci goto error_driver_register; 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci pdev = platform_device_alloc("fsl-of-pamu", 0); 12388c2ecf20Sopenharmony_ci if (!pdev) { 12398c2ecf20Sopenharmony_ci pr_err("could not allocate device %pOF\n", np); 12408c2ecf20Sopenharmony_ci ret = -ENOMEM; 12418c2ecf20Sopenharmony_ci goto error_device_alloc; 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci pdev->dev.of_node = of_node_get(np); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci ret = pamu_domain_init(); 12468c2ecf20Sopenharmony_ci if (ret) 12478c2ecf20Sopenharmony_ci goto error_device_add; 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci ret = platform_device_add(pdev); 12508c2ecf20Sopenharmony_ci if (ret) { 12518c2ecf20Sopenharmony_ci pr_err("could not add device %pOF (err=%i)\n", np, ret); 12528c2ecf20Sopenharmony_ci goto error_device_add; 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci return 0; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_cierror_device_add: 12588c2ecf20Sopenharmony_ci of_node_put(pdev->dev.of_node); 12598c2ecf20Sopenharmony_ci pdev->dev.of_node = NULL; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci platform_device_put(pdev); 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_cierror_device_alloc: 12648c2ecf20Sopenharmony_ci platform_driver_unregister(&fsl_of_pamu_driver); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_cierror_driver_register: 12678c2ecf20Sopenharmony_ci of_node_put(np); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci return ret; 12708c2ecf20Sopenharmony_ci} 12718c2ecf20Sopenharmony_ciarch_initcall(fsl_pamu_init); 1272