162306a36Sopenharmony_ci/* Copyright 2008 - 2016 Freescale Semiconductor, Inc. 262306a36Sopenharmony_ci * 362306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 462306a36Sopenharmony_ci * modification, are permitted provided that the following conditions are met: 562306a36Sopenharmony_ci * * Redistributions of source code must retain the above copyright 662306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 762306a36Sopenharmony_ci * * Redistributions in binary form must reproduce the above copyright 862306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 962306a36Sopenharmony_ci * documentation and/or other materials provided with the distribution. 1062306a36Sopenharmony_ci * * Neither the name of Freescale Semiconductor nor the 1162306a36Sopenharmony_ci * names of its contributors may be used to endorse or promote products 1262306a36Sopenharmony_ci * derived from this software without specific prior written permission. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * ALTERNATIVELY, this software may be distributed under the terms of the 1562306a36Sopenharmony_ci * GNU General Public License ("GPL") as published by the Free Software 1662306a36Sopenharmony_ci * Foundation, either version 2 of that License or (at your option) any 1762306a36Sopenharmony_ci * later version. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY 2062306a36Sopenharmony_ci * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 2162306a36Sopenharmony_ci * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2262306a36Sopenharmony_ci * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY 2362306a36Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2462306a36Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2562306a36Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 2662306a36Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2762306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 2862306a36Sopenharmony_ci * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include "qman_priv.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ciu16 qman_ip_rev; 3462306a36Sopenharmony_ciEXPORT_SYMBOL(qman_ip_rev); 3562306a36Sopenharmony_ciu16 qm_channel_pool1 = QMAN_CHANNEL_POOL1; 3662306a36Sopenharmony_ciEXPORT_SYMBOL(qm_channel_pool1); 3762306a36Sopenharmony_ciu16 qm_channel_caam = QMAN_CHANNEL_CAAM; 3862306a36Sopenharmony_ciEXPORT_SYMBOL(qm_channel_caam); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* Register offsets */ 4162306a36Sopenharmony_ci#define REG_QCSP_LIO_CFG(n) (0x0000 + ((n) * 0x10)) 4262306a36Sopenharmony_ci#define REG_QCSP_IO_CFG(n) (0x0004 + ((n) * 0x10)) 4362306a36Sopenharmony_ci#define REG_QCSP_DD_CFG(n) (0x000c + ((n) * 0x10)) 4462306a36Sopenharmony_ci#define REG_DD_CFG 0x0200 4562306a36Sopenharmony_ci#define REG_DCP_CFG(n) (0x0300 + ((n) * 0x10)) 4662306a36Sopenharmony_ci#define REG_DCP_DD_CFG(n) (0x0304 + ((n) * 0x10)) 4762306a36Sopenharmony_ci#define REG_DCP_DLM_AVG(n) (0x030c + ((n) * 0x10)) 4862306a36Sopenharmony_ci#define REG_PFDR_FPC 0x0400 4962306a36Sopenharmony_ci#define REG_PFDR_FP_HEAD 0x0404 5062306a36Sopenharmony_ci#define REG_PFDR_FP_TAIL 0x0408 5162306a36Sopenharmony_ci#define REG_PFDR_FP_LWIT 0x0410 5262306a36Sopenharmony_ci#define REG_PFDR_CFG 0x0414 5362306a36Sopenharmony_ci#define REG_SFDR_CFG 0x0500 5462306a36Sopenharmony_ci#define REG_SFDR_IN_USE 0x0504 5562306a36Sopenharmony_ci#define REG_WQ_CS_CFG(n) (0x0600 + ((n) * 0x04)) 5662306a36Sopenharmony_ci#define REG_WQ_DEF_ENC_WQID 0x0630 5762306a36Sopenharmony_ci#define REG_WQ_SC_DD_CFG(n) (0x640 + ((n) * 0x04)) 5862306a36Sopenharmony_ci#define REG_WQ_PC_DD_CFG(n) (0x680 + ((n) * 0x04)) 5962306a36Sopenharmony_ci#define REG_WQ_DC0_DD_CFG(n) (0x6c0 + ((n) * 0x04)) 6062306a36Sopenharmony_ci#define REG_WQ_DC1_DD_CFG(n) (0x700 + ((n) * 0x04)) 6162306a36Sopenharmony_ci#define REG_WQ_DCn_DD_CFG(n) (0x6c0 + ((n) * 0x40)) /* n=2,3 */ 6262306a36Sopenharmony_ci#define REG_CM_CFG 0x0800 6362306a36Sopenharmony_ci#define REG_ECSR 0x0a00 6462306a36Sopenharmony_ci#define REG_ECIR 0x0a04 6562306a36Sopenharmony_ci#define REG_EADR 0x0a08 6662306a36Sopenharmony_ci#define REG_ECIR2 0x0a0c 6762306a36Sopenharmony_ci#define REG_EDATA(n) (0x0a10 + ((n) * 0x04)) 6862306a36Sopenharmony_ci#define REG_SBEC(n) (0x0a80 + ((n) * 0x04)) 6962306a36Sopenharmony_ci#define REG_MCR 0x0b00 7062306a36Sopenharmony_ci#define REG_MCP(n) (0x0b04 + ((n) * 0x04)) 7162306a36Sopenharmony_ci#define REG_MISC_CFG 0x0be0 7262306a36Sopenharmony_ci#define REG_HID_CFG 0x0bf0 7362306a36Sopenharmony_ci#define REG_IDLE_STAT 0x0bf4 7462306a36Sopenharmony_ci#define REG_IP_REV_1 0x0bf8 7562306a36Sopenharmony_ci#define REG_IP_REV_2 0x0bfc 7662306a36Sopenharmony_ci#define REG_FQD_BARE 0x0c00 7762306a36Sopenharmony_ci#define REG_PFDR_BARE 0x0c20 7862306a36Sopenharmony_ci#define REG_offset_BAR 0x0004 /* relative to REG_[FQD|PFDR]_BARE */ 7962306a36Sopenharmony_ci#define REG_offset_AR 0x0010 /* relative to REG_[FQD|PFDR]_BARE */ 8062306a36Sopenharmony_ci#define REG_QCSP_BARE 0x0c80 8162306a36Sopenharmony_ci#define REG_QCSP_BAR 0x0c84 8262306a36Sopenharmony_ci#define REG_CI_SCHED_CFG 0x0d00 8362306a36Sopenharmony_ci#define REG_SRCIDR 0x0d04 8462306a36Sopenharmony_ci#define REG_LIODNR 0x0d08 8562306a36Sopenharmony_ci#define REG_CI_RLM_AVG 0x0d14 8662306a36Sopenharmony_ci#define REG_ERR_ISR 0x0e00 8762306a36Sopenharmony_ci#define REG_ERR_IER 0x0e04 8862306a36Sopenharmony_ci#define REG_REV3_QCSP_LIO_CFG(n) (0x1000 + ((n) * 0x10)) 8962306a36Sopenharmony_ci#define REG_REV3_QCSP_IO_CFG(n) (0x1004 + ((n) * 0x10)) 9062306a36Sopenharmony_ci#define REG_REV3_QCSP_DD_CFG(n) (0x100c + ((n) * 0x10)) 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* Assists for QMAN_MCR */ 9362306a36Sopenharmony_ci#define MCR_INIT_PFDR 0x01000000 9462306a36Sopenharmony_ci#define MCR_get_rslt(v) (u8)((v) >> 24) 9562306a36Sopenharmony_ci#define MCR_rslt_idle(r) (!(r) || ((r) >= 0xf0)) 9662306a36Sopenharmony_ci#define MCR_rslt_ok(r) ((r) == 0xf0) 9762306a36Sopenharmony_ci#define MCR_rslt_eaccess(r) ((r) == 0xf8) 9862306a36Sopenharmony_ci#define MCR_rslt_inval(r) ((r) == 0xff) 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* 10162306a36Sopenharmony_ci * Corenet initiator settings. Stash request queues are 4-deep to match cores 10262306a36Sopenharmony_ci * ability to snarf. Stash priority is 3, other priorities are 2. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ci#define QM_CI_SCHED_CFG_SRCCIV 4 10562306a36Sopenharmony_ci#define QM_CI_SCHED_CFG_SRQ_W 3 10662306a36Sopenharmony_ci#define QM_CI_SCHED_CFG_RW_W 2 10762306a36Sopenharmony_ci#define QM_CI_SCHED_CFG_BMAN_W 2 10862306a36Sopenharmony_ci/* write SRCCIV enable */ 10962306a36Sopenharmony_ci#define QM_CI_SCHED_CFG_SRCCIV_EN BIT(31) 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* Follows WQ_CS_CFG0-5 */ 11262306a36Sopenharmony_cienum qm_wq_class { 11362306a36Sopenharmony_ci qm_wq_portal = 0, 11462306a36Sopenharmony_ci qm_wq_pool = 1, 11562306a36Sopenharmony_ci qm_wq_fman0 = 2, 11662306a36Sopenharmony_ci qm_wq_fman1 = 3, 11762306a36Sopenharmony_ci qm_wq_caam = 4, 11862306a36Sopenharmony_ci qm_wq_pme = 5, 11962306a36Sopenharmony_ci qm_wq_first = qm_wq_portal, 12062306a36Sopenharmony_ci qm_wq_last = qm_wq_pme 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* Follows FQD_[BARE|BAR|AR] and PFDR_[BARE|BAR|AR] */ 12462306a36Sopenharmony_cienum qm_memory { 12562306a36Sopenharmony_ci qm_memory_fqd, 12662306a36Sopenharmony_ci qm_memory_pfdr 12762306a36Sopenharmony_ci}; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/* Used by all error interrupt registers except 'inhibit' */ 13062306a36Sopenharmony_ci#define QM_EIRQ_CIDE 0x20000000 /* Corenet Initiator Data Error */ 13162306a36Sopenharmony_ci#define QM_EIRQ_CTDE 0x10000000 /* Corenet Target Data Error */ 13262306a36Sopenharmony_ci#define QM_EIRQ_CITT 0x08000000 /* Corenet Invalid Target Transaction */ 13362306a36Sopenharmony_ci#define QM_EIRQ_PLWI 0x04000000 /* PFDR Low Watermark */ 13462306a36Sopenharmony_ci#define QM_EIRQ_MBEI 0x02000000 /* Multi-bit ECC Error */ 13562306a36Sopenharmony_ci#define QM_EIRQ_SBEI 0x01000000 /* Single-bit ECC Error */ 13662306a36Sopenharmony_ci#define QM_EIRQ_PEBI 0x00800000 /* PFDR Enqueues Blocked Interrupt */ 13762306a36Sopenharmony_ci#define QM_EIRQ_IFSI 0x00020000 /* Invalid FQ Flow Control State */ 13862306a36Sopenharmony_ci#define QM_EIRQ_ICVI 0x00010000 /* Invalid Command Verb */ 13962306a36Sopenharmony_ci#define QM_EIRQ_IDDI 0x00000800 /* Invalid Dequeue (Direct-connect) */ 14062306a36Sopenharmony_ci#define QM_EIRQ_IDFI 0x00000400 /* Invalid Dequeue FQ */ 14162306a36Sopenharmony_ci#define QM_EIRQ_IDSI 0x00000200 /* Invalid Dequeue Source */ 14262306a36Sopenharmony_ci#define QM_EIRQ_IDQI 0x00000100 /* Invalid Dequeue Queue */ 14362306a36Sopenharmony_ci#define QM_EIRQ_IECE 0x00000010 /* Invalid Enqueue Configuration */ 14462306a36Sopenharmony_ci#define QM_EIRQ_IEOI 0x00000008 /* Invalid Enqueue Overflow */ 14562306a36Sopenharmony_ci#define QM_EIRQ_IESI 0x00000004 /* Invalid Enqueue State */ 14662306a36Sopenharmony_ci#define QM_EIRQ_IECI 0x00000002 /* Invalid Enqueue Channel */ 14762306a36Sopenharmony_ci#define QM_EIRQ_IEQI 0x00000001 /* Invalid Enqueue Queue */ 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/* QMAN_ECIR valid error bit */ 15062306a36Sopenharmony_ci#define PORTAL_ECSR_ERR (QM_EIRQ_IEQI | QM_EIRQ_IESI | QM_EIRQ_IEOI | \ 15162306a36Sopenharmony_ci QM_EIRQ_IDQI | QM_EIRQ_IDSI | QM_EIRQ_IDFI | \ 15262306a36Sopenharmony_ci QM_EIRQ_IDDI | QM_EIRQ_ICVI | QM_EIRQ_IFSI) 15362306a36Sopenharmony_ci#define FQID_ECSR_ERR (QM_EIRQ_IEQI | QM_EIRQ_IECI | QM_EIRQ_IESI | \ 15462306a36Sopenharmony_ci QM_EIRQ_IEOI | QM_EIRQ_IDQI | QM_EIRQ_IDFI | \ 15562306a36Sopenharmony_ci QM_EIRQ_IFSI) 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistruct qm_ecir { 15862306a36Sopenharmony_ci u32 info; /* res[30-31], ptyp[29], pnum[24-28], fqid[0-23] */ 15962306a36Sopenharmony_ci}; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic bool qm_ecir_is_dcp(const struct qm_ecir *p) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci return p->info & BIT(29); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic int qm_ecir_get_pnum(const struct qm_ecir *p) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci return (p->info >> 24) & 0x1f; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic int qm_ecir_get_fqid(const struct qm_ecir *p) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci return p->info & (BIT(24) - 1); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistruct qm_ecir2 { 17762306a36Sopenharmony_ci u32 info; /* ptyp[31], res[10-30], pnum[0-9] */ 17862306a36Sopenharmony_ci}; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic bool qm_ecir2_is_dcp(const struct qm_ecir2 *p) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci return p->info & BIT(31); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic int qm_ecir2_get_pnum(const struct qm_ecir2 *p) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci return p->info & (BIT(10) - 1); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistruct qm_eadr { 19162306a36Sopenharmony_ci u32 info; /* memid[24-27], eadr[0-11] */ 19262306a36Sopenharmony_ci /* v3: memid[24-28], eadr[0-15] */ 19362306a36Sopenharmony_ci}; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic int qm_eadr_get_memid(const struct qm_eadr *p) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci return (p->info >> 24) & 0xf; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic int qm_eadr_get_eadr(const struct qm_eadr *p) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci return p->info & (BIT(12) - 1); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic int qm_eadr_v3_get_memid(const struct qm_eadr *p) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci return (p->info >> 24) & 0x1f; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic int qm_eadr_v3_get_eadr(const struct qm_eadr *p) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci return p->info & (BIT(16) - 1); 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistruct qman_hwerr_txt { 21662306a36Sopenharmony_ci u32 mask; 21762306a36Sopenharmony_ci const char *txt; 21862306a36Sopenharmony_ci}; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic const struct qman_hwerr_txt qman_hwerr_txts[] = { 22262306a36Sopenharmony_ci { QM_EIRQ_CIDE, "Corenet Initiator Data Error" }, 22362306a36Sopenharmony_ci { QM_EIRQ_CTDE, "Corenet Target Data Error" }, 22462306a36Sopenharmony_ci { QM_EIRQ_CITT, "Corenet Invalid Target Transaction" }, 22562306a36Sopenharmony_ci { QM_EIRQ_PLWI, "PFDR Low Watermark" }, 22662306a36Sopenharmony_ci { QM_EIRQ_MBEI, "Multi-bit ECC Error" }, 22762306a36Sopenharmony_ci { QM_EIRQ_SBEI, "Single-bit ECC Error" }, 22862306a36Sopenharmony_ci { QM_EIRQ_PEBI, "PFDR Enqueues Blocked Interrupt" }, 22962306a36Sopenharmony_ci { QM_EIRQ_ICVI, "Invalid Command Verb" }, 23062306a36Sopenharmony_ci { QM_EIRQ_IFSI, "Invalid Flow Control State" }, 23162306a36Sopenharmony_ci { QM_EIRQ_IDDI, "Invalid Dequeue (Direct-connect)" }, 23262306a36Sopenharmony_ci { QM_EIRQ_IDFI, "Invalid Dequeue FQ" }, 23362306a36Sopenharmony_ci { QM_EIRQ_IDSI, "Invalid Dequeue Source" }, 23462306a36Sopenharmony_ci { QM_EIRQ_IDQI, "Invalid Dequeue Queue" }, 23562306a36Sopenharmony_ci { QM_EIRQ_IECE, "Invalid Enqueue Configuration" }, 23662306a36Sopenharmony_ci { QM_EIRQ_IEOI, "Invalid Enqueue Overflow" }, 23762306a36Sopenharmony_ci { QM_EIRQ_IESI, "Invalid Enqueue State" }, 23862306a36Sopenharmony_ci { QM_EIRQ_IECI, "Invalid Enqueue Channel" }, 23962306a36Sopenharmony_ci { QM_EIRQ_IEQI, "Invalid Enqueue Queue" }, 24062306a36Sopenharmony_ci}; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistruct qman_error_info_mdata { 24362306a36Sopenharmony_ci u16 addr_mask; 24462306a36Sopenharmony_ci u16 bits; 24562306a36Sopenharmony_ci const char *txt; 24662306a36Sopenharmony_ci}; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic const struct qman_error_info_mdata error_mdata[] = { 24962306a36Sopenharmony_ci { 0x01FF, 24, "FQD cache tag memory 0" }, 25062306a36Sopenharmony_ci { 0x01FF, 24, "FQD cache tag memory 1" }, 25162306a36Sopenharmony_ci { 0x01FF, 24, "FQD cache tag memory 2" }, 25262306a36Sopenharmony_ci { 0x01FF, 24, "FQD cache tag memory 3" }, 25362306a36Sopenharmony_ci { 0x0FFF, 512, "FQD cache memory" }, 25462306a36Sopenharmony_ci { 0x07FF, 128, "SFDR memory" }, 25562306a36Sopenharmony_ci { 0x01FF, 72, "WQ context memory" }, 25662306a36Sopenharmony_ci { 0x00FF, 240, "CGR memory" }, 25762306a36Sopenharmony_ci { 0x00FF, 302, "Internal Order Restoration List memory" }, 25862306a36Sopenharmony_ci { 0x01FF, 256, "SW portal ring memory" }, 25962306a36Sopenharmony_ci}; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci#define QMAN_ERRS_TO_DISABLE (QM_EIRQ_PLWI | QM_EIRQ_PEBI) 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci/* 26462306a36Sopenharmony_ci * TODO: unimplemented registers 26562306a36Sopenharmony_ci * 26662306a36Sopenharmony_ci * Keeping a list here of QMan registers I have not yet covered; 26762306a36Sopenharmony_ci * QCSP_DD_IHRSR, QCSP_DD_IHRFR, QCSP_DD_HASR, 26862306a36Sopenharmony_ci * DCP_DD_IHRSR, DCP_DD_IHRFR, DCP_DD_HASR, CM_CFG, 26962306a36Sopenharmony_ci * QMAN_EECC, QMAN_SBET, QMAN_EINJ, QMAN_SBEC0-12 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/* Pointer to the start of the QMan's CCSR space */ 27362306a36Sopenharmony_cistatic u32 __iomem *qm_ccsr_start; 27462306a36Sopenharmony_ci/* A SDQCR mask comprising all the available/visible pool channels */ 27562306a36Sopenharmony_cistatic u32 qm_pools_sdqcr; 27662306a36Sopenharmony_cistatic int __qman_probed; 27762306a36Sopenharmony_cistatic int __qman_requires_cleanup; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic inline u32 qm_ccsr_in(u32 offset) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci return ioread32be(qm_ccsr_start + offset/4); 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic inline void qm_ccsr_out(u32 offset, u32 val) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci iowrite32be(val, qm_ccsr_start + offset/4); 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ciu32 qm_get_pools_sdqcr(void) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci return qm_pools_sdqcr; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cienum qm_dc_portal { 29562306a36Sopenharmony_ci qm_dc_portal_fman0 = 0, 29662306a36Sopenharmony_ci qm_dc_portal_fman1 = 1 29762306a36Sopenharmony_ci}; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic void qm_set_dc(enum qm_dc_portal portal, int ed, u8 sernd) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci DPAA_ASSERT(!ed || portal == qm_dc_portal_fman0 || 30262306a36Sopenharmony_ci portal == qm_dc_portal_fman1); 30362306a36Sopenharmony_ci if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) 30462306a36Sopenharmony_ci qm_ccsr_out(REG_DCP_CFG(portal), 30562306a36Sopenharmony_ci (ed ? 0x1000 : 0) | (sernd & 0x3ff)); 30662306a36Sopenharmony_ci else 30762306a36Sopenharmony_ci qm_ccsr_out(REG_DCP_CFG(portal), 30862306a36Sopenharmony_ci (ed ? 0x100 : 0) | (sernd & 0x1f)); 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic void qm_set_wq_scheduling(enum qm_wq_class wq_class, 31262306a36Sopenharmony_ci u8 cs_elev, u8 csw2, u8 csw3, u8 csw4, 31362306a36Sopenharmony_ci u8 csw5, u8 csw6, u8 csw7) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci qm_ccsr_out(REG_WQ_CS_CFG(wq_class), ((cs_elev & 0xff) << 24) | 31662306a36Sopenharmony_ci ((csw2 & 0x7) << 20) | ((csw3 & 0x7) << 16) | 31762306a36Sopenharmony_ci ((csw4 & 0x7) << 12) | ((csw5 & 0x7) << 8) | 31862306a36Sopenharmony_ci ((csw6 & 0x7) << 4) | (csw7 & 0x7)); 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic void qm_set_hid(void) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci qm_ccsr_out(REG_HID_CFG, 0); 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic void qm_set_corenet_initiator(void) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci qm_ccsr_out(REG_CI_SCHED_CFG, QM_CI_SCHED_CFG_SRCCIV_EN | 32962306a36Sopenharmony_ci (QM_CI_SCHED_CFG_SRCCIV << 24) | 33062306a36Sopenharmony_ci (QM_CI_SCHED_CFG_SRQ_W << 8) | 33162306a36Sopenharmony_ci (QM_CI_SCHED_CFG_RW_W << 4) | 33262306a36Sopenharmony_ci QM_CI_SCHED_CFG_BMAN_W); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic void qm_get_version(u16 *id, u8 *major, u8 *minor) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci u32 v = qm_ccsr_in(REG_IP_REV_1); 33862306a36Sopenharmony_ci *id = (v >> 16); 33962306a36Sopenharmony_ci *major = (v >> 8) & 0xff; 34062306a36Sopenharmony_ci *minor = v & 0xff; 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci#define PFDR_AR_EN BIT(31) 34462306a36Sopenharmony_cistatic int qm_set_memory(enum qm_memory memory, u64 ba, u32 size) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci void *ptr; 34762306a36Sopenharmony_ci u32 offset = (memory == qm_memory_fqd) ? REG_FQD_BARE : REG_PFDR_BARE; 34862306a36Sopenharmony_ci u32 exp = ilog2(size); 34962306a36Sopenharmony_ci u32 bar, bare; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* choke if size isn't within range */ 35262306a36Sopenharmony_ci DPAA_ASSERT((size >= 4096) && (size <= 1024*1024*1024) && 35362306a36Sopenharmony_ci is_power_of_2(size)); 35462306a36Sopenharmony_ci /* choke if 'ba' has lower-alignment than 'size' */ 35562306a36Sopenharmony_ci DPAA_ASSERT(!(ba & (size - 1))); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* Check to see if QMan has already been initialized */ 35862306a36Sopenharmony_ci bar = qm_ccsr_in(offset + REG_offset_BAR); 35962306a36Sopenharmony_ci if (bar) { 36062306a36Sopenharmony_ci /* Maker sure ba == what was programmed) */ 36162306a36Sopenharmony_ci bare = qm_ccsr_in(offset); 36262306a36Sopenharmony_ci if (bare != upper_32_bits(ba) || bar != lower_32_bits(ba)) { 36362306a36Sopenharmony_ci pr_err("Attempted to reinitialize QMan with different BAR, got 0x%llx read BARE=0x%x BAR=0x%x\n", 36462306a36Sopenharmony_ci ba, bare, bar); 36562306a36Sopenharmony_ci return -ENOMEM; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci __qman_requires_cleanup = 1; 36862306a36Sopenharmony_ci /* Return 1 to indicate memory was previously programmed */ 36962306a36Sopenharmony_ci return 1; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci /* Need to temporarily map the area to make sure it is zeroed */ 37262306a36Sopenharmony_ci ptr = memremap(ba, size, MEMREMAP_WB); 37362306a36Sopenharmony_ci if (!ptr) { 37462306a36Sopenharmony_ci pr_crit("memremap() of QMan private memory failed\n"); 37562306a36Sopenharmony_ci return -ENOMEM; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci memset(ptr, 0, size); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci#ifdef CONFIG_PPC 38062306a36Sopenharmony_ci /* 38162306a36Sopenharmony_ci * PPC doesn't appear to flush the cache on memunmap() but the 38262306a36Sopenharmony_ci * cache must be flushed since QMan does non coherent accesses 38362306a36Sopenharmony_ci * to this memory 38462306a36Sopenharmony_ci */ 38562306a36Sopenharmony_ci flush_dcache_range((unsigned long) ptr, (unsigned long) ptr+size); 38662306a36Sopenharmony_ci#endif 38762306a36Sopenharmony_ci memunmap(ptr); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci qm_ccsr_out(offset, upper_32_bits(ba)); 39062306a36Sopenharmony_ci qm_ccsr_out(offset + REG_offset_BAR, lower_32_bits(ba)); 39162306a36Sopenharmony_ci qm_ccsr_out(offset + REG_offset_AR, PFDR_AR_EN | (exp - 1)); 39262306a36Sopenharmony_ci return 0; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic void qm_set_pfdr_threshold(u32 th, u8 k) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci qm_ccsr_out(REG_PFDR_FP_LWIT, th & 0xffffff); 39862306a36Sopenharmony_ci qm_ccsr_out(REG_PFDR_CFG, k); 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic void qm_set_sfdr_threshold(u16 th) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci qm_ccsr_out(REG_SFDR_CFG, th & 0x3ff); 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic int qm_init_pfdr(struct device *dev, u32 pfdr_start, u32 num) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci u8 rslt = MCR_get_rslt(qm_ccsr_in(REG_MCR)); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci DPAA_ASSERT(pfdr_start && !(pfdr_start & 7) && !(num & 7) && num); 41162306a36Sopenharmony_ci /* Make sure the command interface is 'idle' */ 41262306a36Sopenharmony_ci if (!MCR_rslt_idle(rslt)) { 41362306a36Sopenharmony_ci dev_crit(dev, "QMAN_MCR isn't idle"); 41462306a36Sopenharmony_ci WARN_ON(1); 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci /* Write the MCR command params then the verb */ 41862306a36Sopenharmony_ci qm_ccsr_out(REG_MCP(0), pfdr_start); 41962306a36Sopenharmony_ci /* 42062306a36Sopenharmony_ci * TODO: remove this - it's a workaround for a model bug that is 42162306a36Sopenharmony_ci * corrected in more recent versions. We use the workaround until 42262306a36Sopenharmony_ci * everyone has upgraded. 42362306a36Sopenharmony_ci */ 42462306a36Sopenharmony_ci qm_ccsr_out(REG_MCP(1), pfdr_start + num - 16); 42562306a36Sopenharmony_ci dma_wmb(); 42662306a36Sopenharmony_ci qm_ccsr_out(REG_MCR, MCR_INIT_PFDR); 42762306a36Sopenharmony_ci /* Poll for the result */ 42862306a36Sopenharmony_ci do { 42962306a36Sopenharmony_ci rslt = MCR_get_rslt(qm_ccsr_in(REG_MCR)); 43062306a36Sopenharmony_ci } while (!MCR_rslt_idle(rslt)); 43162306a36Sopenharmony_ci if (MCR_rslt_ok(rslt)) 43262306a36Sopenharmony_ci return 0; 43362306a36Sopenharmony_ci if (MCR_rslt_eaccess(rslt)) 43462306a36Sopenharmony_ci return -EACCES; 43562306a36Sopenharmony_ci if (MCR_rslt_inval(rslt)) 43662306a36Sopenharmony_ci return -EINVAL; 43762306a36Sopenharmony_ci dev_crit(dev, "Unexpected result from MCR_INIT_PFDR: %02x\n", rslt); 43862306a36Sopenharmony_ci return -ENODEV; 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci/* 44262306a36Sopenharmony_ci * QMan needs two global memory areas initialized at boot time: 44362306a36Sopenharmony_ci * 1) FQD: Frame Queue Descriptors used to manage frame queues 44462306a36Sopenharmony_ci * 2) PFDR: Packed Frame Queue Descriptor Records used to store frames 44562306a36Sopenharmony_ci * Both areas are reserved using the device tree reserved memory framework 44662306a36Sopenharmony_ci * and the addresses and sizes are initialized when the QMan device is probed 44762306a36Sopenharmony_ci */ 44862306a36Sopenharmony_cistatic dma_addr_t fqd_a, pfdr_a; 44962306a36Sopenharmony_cistatic size_t fqd_sz, pfdr_sz; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci#ifdef CONFIG_PPC 45262306a36Sopenharmony_ci/* 45362306a36Sopenharmony_ci * Support for PPC Device Tree backward compatibility when compatible 45462306a36Sopenharmony_ci * string is set to fsl-qman-fqd and fsl-qman-pfdr 45562306a36Sopenharmony_ci */ 45662306a36Sopenharmony_cistatic int zero_priv_mem(phys_addr_t addr, size_t sz) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci /* map as cacheable, non-guarded */ 45962306a36Sopenharmony_ci void __iomem *tmpp = ioremap_cache(addr, sz); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (!tmpp) 46262306a36Sopenharmony_ci return -ENOMEM; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci memset_io(tmpp, 0, sz); 46562306a36Sopenharmony_ci flush_dcache_range((unsigned long)tmpp, 46662306a36Sopenharmony_ci (unsigned long)tmpp + sz); 46762306a36Sopenharmony_ci iounmap(tmpp); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci return 0; 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic int qman_fqd(struct reserved_mem *rmem) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci fqd_a = rmem->base; 47562306a36Sopenharmony_ci fqd_sz = rmem->size; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci WARN_ON(!(fqd_a && fqd_sz)); 47862306a36Sopenharmony_ci return 0; 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ciRESERVEDMEM_OF_DECLARE(qman_fqd, "fsl,qman-fqd", qman_fqd); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic int qman_pfdr(struct reserved_mem *rmem) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci pfdr_a = rmem->base; 48562306a36Sopenharmony_ci pfdr_sz = rmem->size; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci WARN_ON(!(pfdr_a && pfdr_sz)); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci return 0; 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ciRESERVEDMEM_OF_DECLARE(qman_pfdr, "fsl,qman-pfdr", qman_pfdr); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci#endif 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ciunsigned int qm_get_fqid_maxcnt(void) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci return fqd_sz / 64; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic void log_edata_bits(struct device *dev, u32 bit_count) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci u32 i, j, mask = 0xffffffff; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci dev_warn(dev, "ErrInt, EDATA:\n"); 50562306a36Sopenharmony_ci i = bit_count / 32; 50662306a36Sopenharmony_ci if (bit_count % 32) { 50762306a36Sopenharmony_ci i++; 50862306a36Sopenharmony_ci mask = ~(mask << bit_count % 32); 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci j = 16 - i; 51162306a36Sopenharmony_ci dev_warn(dev, " 0x%08x\n", qm_ccsr_in(REG_EDATA(j)) & mask); 51262306a36Sopenharmony_ci j++; 51362306a36Sopenharmony_ci for (; j < 16; j++) 51462306a36Sopenharmony_ci dev_warn(dev, " 0x%08x\n", qm_ccsr_in(REG_EDATA(j))); 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic void log_additional_error_info(struct device *dev, u32 isr_val, 51862306a36Sopenharmony_ci u32 ecsr_val) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct qm_ecir ecir_val; 52162306a36Sopenharmony_ci struct qm_eadr eadr_val; 52262306a36Sopenharmony_ci int memid; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci ecir_val.info = qm_ccsr_in(REG_ECIR); 52562306a36Sopenharmony_ci /* Is portal info valid */ 52662306a36Sopenharmony_ci if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) { 52762306a36Sopenharmony_ci struct qm_ecir2 ecir2_val; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci ecir2_val.info = qm_ccsr_in(REG_ECIR2); 53062306a36Sopenharmony_ci if (ecsr_val & PORTAL_ECSR_ERR) { 53162306a36Sopenharmony_ci dev_warn(dev, "ErrInt: %s id %d\n", 53262306a36Sopenharmony_ci qm_ecir2_is_dcp(&ecir2_val) ? "DCP" : "SWP", 53362306a36Sopenharmony_ci qm_ecir2_get_pnum(&ecir2_val)); 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci if (ecsr_val & (FQID_ECSR_ERR | QM_EIRQ_IECE)) 53662306a36Sopenharmony_ci dev_warn(dev, "ErrInt: ecir.fqid 0x%x\n", 53762306a36Sopenharmony_ci qm_ecir_get_fqid(&ecir_val)); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci if (ecsr_val & (QM_EIRQ_SBEI|QM_EIRQ_MBEI)) { 54062306a36Sopenharmony_ci eadr_val.info = qm_ccsr_in(REG_EADR); 54162306a36Sopenharmony_ci memid = qm_eadr_v3_get_memid(&eadr_val); 54262306a36Sopenharmony_ci dev_warn(dev, "ErrInt: EADR Memory: %s, 0x%x\n", 54362306a36Sopenharmony_ci error_mdata[memid].txt, 54462306a36Sopenharmony_ci error_mdata[memid].addr_mask 54562306a36Sopenharmony_ci & qm_eadr_v3_get_eadr(&eadr_val)); 54662306a36Sopenharmony_ci log_edata_bits(dev, error_mdata[memid].bits); 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci } else { 54962306a36Sopenharmony_ci if (ecsr_val & PORTAL_ECSR_ERR) { 55062306a36Sopenharmony_ci dev_warn(dev, "ErrInt: %s id %d\n", 55162306a36Sopenharmony_ci qm_ecir_is_dcp(&ecir_val) ? "DCP" : "SWP", 55262306a36Sopenharmony_ci qm_ecir_get_pnum(&ecir_val)); 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci if (ecsr_val & FQID_ECSR_ERR) 55562306a36Sopenharmony_ci dev_warn(dev, "ErrInt: ecir.fqid 0x%x\n", 55662306a36Sopenharmony_ci qm_ecir_get_fqid(&ecir_val)); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci if (ecsr_val & (QM_EIRQ_SBEI|QM_EIRQ_MBEI)) { 55962306a36Sopenharmony_ci eadr_val.info = qm_ccsr_in(REG_EADR); 56062306a36Sopenharmony_ci memid = qm_eadr_get_memid(&eadr_val); 56162306a36Sopenharmony_ci dev_warn(dev, "ErrInt: EADR Memory: %s, 0x%x\n", 56262306a36Sopenharmony_ci error_mdata[memid].txt, 56362306a36Sopenharmony_ci error_mdata[memid].addr_mask 56462306a36Sopenharmony_ci & qm_eadr_get_eadr(&eadr_val)); 56562306a36Sopenharmony_ci log_edata_bits(dev, error_mdata[memid].bits); 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic irqreturn_t qman_isr(int irq, void *ptr) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci u32 isr_val, ier_val, ecsr_val, isr_mask, i; 57362306a36Sopenharmony_ci struct device *dev = ptr; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci ier_val = qm_ccsr_in(REG_ERR_IER); 57662306a36Sopenharmony_ci isr_val = qm_ccsr_in(REG_ERR_ISR); 57762306a36Sopenharmony_ci ecsr_val = qm_ccsr_in(REG_ECSR); 57862306a36Sopenharmony_ci isr_mask = isr_val & ier_val; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci if (!isr_mask) 58162306a36Sopenharmony_ci return IRQ_NONE; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(qman_hwerr_txts); i++) { 58462306a36Sopenharmony_ci if (qman_hwerr_txts[i].mask & isr_mask) { 58562306a36Sopenharmony_ci dev_err_ratelimited(dev, "ErrInt: %s\n", 58662306a36Sopenharmony_ci qman_hwerr_txts[i].txt); 58762306a36Sopenharmony_ci if (qman_hwerr_txts[i].mask & ecsr_val) { 58862306a36Sopenharmony_ci log_additional_error_info(dev, isr_mask, 58962306a36Sopenharmony_ci ecsr_val); 59062306a36Sopenharmony_ci /* Re-arm error capture registers */ 59162306a36Sopenharmony_ci qm_ccsr_out(REG_ECSR, ecsr_val); 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci if (qman_hwerr_txts[i].mask & QMAN_ERRS_TO_DISABLE) { 59462306a36Sopenharmony_ci dev_dbg(dev, "Disabling error 0x%x\n", 59562306a36Sopenharmony_ci qman_hwerr_txts[i].mask); 59662306a36Sopenharmony_ci ier_val &= ~qman_hwerr_txts[i].mask; 59762306a36Sopenharmony_ci qm_ccsr_out(REG_ERR_IER, ier_val); 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci qm_ccsr_out(REG_ERR_ISR, isr_val); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci return IRQ_HANDLED; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic int qman_init_ccsr(struct device *dev) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci int i, err; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci /* FQD memory */ 61162306a36Sopenharmony_ci err = qm_set_memory(qm_memory_fqd, fqd_a, fqd_sz); 61262306a36Sopenharmony_ci if (err < 0) 61362306a36Sopenharmony_ci return err; 61462306a36Sopenharmony_ci /* PFDR memory */ 61562306a36Sopenharmony_ci err = qm_set_memory(qm_memory_pfdr, pfdr_a, pfdr_sz); 61662306a36Sopenharmony_ci if (err < 0) 61762306a36Sopenharmony_ci return err; 61862306a36Sopenharmony_ci /* Only initialize PFDRs if the QMan was not initialized before */ 61962306a36Sopenharmony_ci if (err == 0) { 62062306a36Sopenharmony_ci err = qm_init_pfdr(dev, 8, pfdr_sz / 64 - 8); 62162306a36Sopenharmony_ci if (err) 62262306a36Sopenharmony_ci return err; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci /* thresholds */ 62562306a36Sopenharmony_ci qm_set_pfdr_threshold(512, 64); 62662306a36Sopenharmony_ci qm_set_sfdr_threshold(128); 62762306a36Sopenharmony_ci /* clear stale PEBI bit from interrupt status register */ 62862306a36Sopenharmony_ci qm_ccsr_out(REG_ERR_ISR, QM_EIRQ_PEBI); 62962306a36Sopenharmony_ci /* corenet initiator settings */ 63062306a36Sopenharmony_ci qm_set_corenet_initiator(); 63162306a36Sopenharmony_ci /* HID settings */ 63262306a36Sopenharmony_ci qm_set_hid(); 63362306a36Sopenharmony_ci /* Set scheduling weights to defaults */ 63462306a36Sopenharmony_ci for (i = qm_wq_first; i <= qm_wq_last; i++) 63562306a36Sopenharmony_ci qm_set_wq_scheduling(i, 0, 0, 0, 0, 0, 0, 0); 63662306a36Sopenharmony_ci /* We are not prepared to accept ERNs for hardware enqueues */ 63762306a36Sopenharmony_ci qm_set_dc(qm_dc_portal_fman0, 1, 0); 63862306a36Sopenharmony_ci qm_set_dc(qm_dc_portal_fman1, 1, 0); 63962306a36Sopenharmony_ci return 0; 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci#define LIO_CFG_LIODN_MASK 0x0fff0000 64362306a36Sopenharmony_civoid __qman_liodn_fixup(u16 channel) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci static int done; 64662306a36Sopenharmony_ci static u32 liodn_offset; 64762306a36Sopenharmony_ci u32 before, after; 64862306a36Sopenharmony_ci int idx = channel - QM_CHANNEL_SWPORTAL0; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) 65162306a36Sopenharmony_ci before = qm_ccsr_in(REG_REV3_QCSP_LIO_CFG(idx)); 65262306a36Sopenharmony_ci else 65362306a36Sopenharmony_ci before = qm_ccsr_in(REG_QCSP_LIO_CFG(idx)); 65462306a36Sopenharmony_ci if (!done) { 65562306a36Sopenharmony_ci liodn_offset = before & LIO_CFG_LIODN_MASK; 65662306a36Sopenharmony_ci done = 1; 65762306a36Sopenharmony_ci return; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci after = (before & (~LIO_CFG_LIODN_MASK)) | liodn_offset; 66062306a36Sopenharmony_ci if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) 66162306a36Sopenharmony_ci qm_ccsr_out(REG_REV3_QCSP_LIO_CFG(idx), after); 66262306a36Sopenharmony_ci else 66362306a36Sopenharmony_ci qm_ccsr_out(REG_QCSP_LIO_CFG(idx), after); 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci#define IO_CFG_SDEST_MASK 0x00ff0000 66762306a36Sopenharmony_civoid qman_set_sdest(u16 channel, unsigned int cpu_idx) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci int idx = channel - QM_CHANNEL_SWPORTAL0; 67062306a36Sopenharmony_ci u32 before, after; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) { 67362306a36Sopenharmony_ci before = qm_ccsr_in(REG_REV3_QCSP_IO_CFG(idx)); 67462306a36Sopenharmony_ci /* Each pair of vcpu share the same SRQ(SDEST) */ 67562306a36Sopenharmony_ci cpu_idx /= 2; 67662306a36Sopenharmony_ci after = (before & (~IO_CFG_SDEST_MASK)) | (cpu_idx << 16); 67762306a36Sopenharmony_ci qm_ccsr_out(REG_REV3_QCSP_IO_CFG(idx), after); 67862306a36Sopenharmony_ci } else { 67962306a36Sopenharmony_ci before = qm_ccsr_in(REG_QCSP_IO_CFG(idx)); 68062306a36Sopenharmony_ci after = (before & (~IO_CFG_SDEST_MASK)) | (cpu_idx << 16); 68162306a36Sopenharmony_ci qm_ccsr_out(REG_QCSP_IO_CFG(idx), after); 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic int qman_resource_init(struct device *dev) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci int pool_chan_num, cgrid_num; 68862306a36Sopenharmony_ci int ret, i; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci switch (qman_ip_rev >> 8) { 69162306a36Sopenharmony_ci case 1: 69262306a36Sopenharmony_ci pool_chan_num = 15; 69362306a36Sopenharmony_ci cgrid_num = 256; 69462306a36Sopenharmony_ci break; 69562306a36Sopenharmony_ci case 2: 69662306a36Sopenharmony_ci pool_chan_num = 3; 69762306a36Sopenharmony_ci cgrid_num = 64; 69862306a36Sopenharmony_ci break; 69962306a36Sopenharmony_ci case 3: 70062306a36Sopenharmony_ci pool_chan_num = 15; 70162306a36Sopenharmony_ci cgrid_num = 256; 70262306a36Sopenharmony_ci break; 70362306a36Sopenharmony_ci default: 70462306a36Sopenharmony_ci return -ENODEV; 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci ret = gen_pool_add(qm_qpalloc, qm_channel_pool1 | DPAA_GENALLOC_OFF, 70862306a36Sopenharmony_ci pool_chan_num, -1); 70962306a36Sopenharmony_ci if (ret) { 71062306a36Sopenharmony_ci dev_err(dev, "Failed to seed pool channels (%d)\n", ret); 71162306a36Sopenharmony_ci return ret; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci ret = gen_pool_add(qm_cgralloc, DPAA_GENALLOC_OFF, cgrid_num, -1); 71562306a36Sopenharmony_ci if (ret) { 71662306a36Sopenharmony_ci dev_err(dev, "Failed to seed CGRID range (%d)\n", ret); 71762306a36Sopenharmony_ci return ret; 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci /* parse pool channels into the SDQCR mask */ 72162306a36Sopenharmony_ci for (i = 0; i < cgrid_num; i++) 72262306a36Sopenharmony_ci qm_pools_sdqcr |= QM_SDQCR_CHANNELS_POOL_CONV(i); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci ret = gen_pool_add(qm_fqalloc, QM_FQID_RANGE_START | DPAA_GENALLOC_OFF, 72562306a36Sopenharmony_ci qm_get_fqid_maxcnt() - QM_FQID_RANGE_START, -1); 72662306a36Sopenharmony_ci if (ret) { 72762306a36Sopenharmony_ci dev_err(dev, "Failed to seed FQID range (%d)\n", ret); 72862306a36Sopenharmony_ci return ret; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci return 0; 73262306a36Sopenharmony_ci} 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ciint qman_is_probed(void) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci return __qman_probed; 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(qman_is_probed); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ciint qman_requires_cleanup(void) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci return __qman_requires_cleanup; 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_civoid qman_done_cleanup(void) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci qman_enable_irqs(); 74862306a36Sopenharmony_ci __qman_requires_cleanup = 0; 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_cistatic int fsl_qman_probe(struct platform_device *pdev) 75362306a36Sopenharmony_ci{ 75462306a36Sopenharmony_ci struct device *dev = &pdev->dev; 75562306a36Sopenharmony_ci struct device_node *node = dev->of_node; 75662306a36Sopenharmony_ci struct resource *res; 75762306a36Sopenharmony_ci int ret, err_irq; 75862306a36Sopenharmony_ci u16 id; 75962306a36Sopenharmony_ci u8 major, minor; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci __qman_probed = -1; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 76462306a36Sopenharmony_ci if (!res) { 76562306a36Sopenharmony_ci dev_err(dev, "Can't get %pOF property 'IORESOURCE_MEM'\n", 76662306a36Sopenharmony_ci node); 76762306a36Sopenharmony_ci return -ENXIO; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci qm_ccsr_start = devm_ioremap(dev, res->start, resource_size(res)); 77062306a36Sopenharmony_ci if (!qm_ccsr_start) 77162306a36Sopenharmony_ci return -ENXIO; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci qm_get_version(&id, &major, &minor); 77462306a36Sopenharmony_ci if (major == 1 && minor == 0) { 77562306a36Sopenharmony_ci dev_err(dev, "Rev1.0 on P4080 rev1 is not supported!\n"); 77662306a36Sopenharmony_ci return -ENODEV; 77762306a36Sopenharmony_ci } else if (major == 1 && minor == 1) 77862306a36Sopenharmony_ci qman_ip_rev = QMAN_REV11; 77962306a36Sopenharmony_ci else if (major == 1 && minor == 2) 78062306a36Sopenharmony_ci qman_ip_rev = QMAN_REV12; 78162306a36Sopenharmony_ci else if (major == 2 && minor == 0) 78262306a36Sopenharmony_ci qman_ip_rev = QMAN_REV20; 78362306a36Sopenharmony_ci else if (major == 3 && minor == 0) 78462306a36Sopenharmony_ci qman_ip_rev = QMAN_REV30; 78562306a36Sopenharmony_ci else if (major == 3 && minor == 1) 78662306a36Sopenharmony_ci qman_ip_rev = QMAN_REV31; 78762306a36Sopenharmony_ci else if (major == 3 && minor == 2) 78862306a36Sopenharmony_ci qman_ip_rev = QMAN_REV32; 78962306a36Sopenharmony_ci else { 79062306a36Sopenharmony_ci dev_err(dev, "Unknown QMan version\n"); 79162306a36Sopenharmony_ci return -ENODEV; 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci if ((qman_ip_rev & 0xff00) >= QMAN_REV30) { 79562306a36Sopenharmony_ci qm_channel_pool1 = QMAN_CHANNEL_POOL1_REV3; 79662306a36Sopenharmony_ci qm_channel_caam = QMAN_CHANNEL_CAAM_REV3; 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci if (fqd_a) { 80062306a36Sopenharmony_ci#ifdef CONFIG_PPC 80162306a36Sopenharmony_ci /* 80262306a36Sopenharmony_ci * For PPC backward DT compatibility 80362306a36Sopenharmony_ci * FQD memory MUST be zero'd by software 80462306a36Sopenharmony_ci */ 80562306a36Sopenharmony_ci zero_priv_mem(fqd_a, fqd_sz); 80662306a36Sopenharmony_ci#else 80762306a36Sopenharmony_ci WARN(1, "Unexpected architecture using non shared-dma-mem reservations"); 80862306a36Sopenharmony_ci#endif 80962306a36Sopenharmony_ci } else { 81062306a36Sopenharmony_ci /* 81162306a36Sopenharmony_ci * Order of memory regions is assumed as FQD followed by PFDR 81262306a36Sopenharmony_ci * in order to ensure allocations from the correct regions the 81362306a36Sopenharmony_ci * driver initializes then allocates each piece in order 81462306a36Sopenharmony_ci */ 81562306a36Sopenharmony_ci ret = qbman_init_private_mem(dev, 0, &fqd_a, &fqd_sz); 81662306a36Sopenharmony_ci if (ret) { 81762306a36Sopenharmony_ci dev_err(dev, "qbman_init_private_mem() for FQD failed 0x%x\n", 81862306a36Sopenharmony_ci ret); 81962306a36Sopenharmony_ci return -ENODEV; 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci dev_dbg(dev, "Allocated FQD 0x%llx 0x%zx\n", fqd_a, fqd_sz); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci if (!pfdr_a) { 82562306a36Sopenharmony_ci /* Setup PFDR memory */ 82662306a36Sopenharmony_ci ret = qbman_init_private_mem(dev, 1, &pfdr_a, &pfdr_sz); 82762306a36Sopenharmony_ci if (ret) { 82862306a36Sopenharmony_ci dev_err(dev, "qbman_init_private_mem() for PFDR failed 0x%x\n", 82962306a36Sopenharmony_ci ret); 83062306a36Sopenharmony_ci return -ENODEV; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci dev_dbg(dev, "Allocated PFDR 0x%llx 0x%zx\n", pfdr_a, pfdr_sz); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci ret = qman_init_ccsr(dev); 83662306a36Sopenharmony_ci if (ret) { 83762306a36Sopenharmony_ci dev_err(dev, "CCSR setup failed\n"); 83862306a36Sopenharmony_ci return ret; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci err_irq = platform_get_irq(pdev, 0); 84262306a36Sopenharmony_ci if (err_irq <= 0) { 84362306a36Sopenharmony_ci dev_info(dev, "Can't get %pOF property 'interrupts'\n", 84462306a36Sopenharmony_ci node); 84562306a36Sopenharmony_ci return -ENODEV; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci ret = devm_request_irq(dev, err_irq, qman_isr, IRQF_SHARED, "qman-err", 84862306a36Sopenharmony_ci dev); 84962306a36Sopenharmony_ci if (ret) { 85062306a36Sopenharmony_ci dev_err(dev, "devm_request_irq() failed %d for '%pOF'\n", 85162306a36Sopenharmony_ci ret, node); 85262306a36Sopenharmony_ci return ret; 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci /* 85662306a36Sopenharmony_ci * Write-to-clear any stale bits, (eg. starvation being asserted prior 85762306a36Sopenharmony_ci * to resource allocation during driver init). 85862306a36Sopenharmony_ci */ 85962306a36Sopenharmony_ci qm_ccsr_out(REG_ERR_ISR, 0xffffffff); 86062306a36Sopenharmony_ci /* Enable Error Interrupts */ 86162306a36Sopenharmony_ci qm_ccsr_out(REG_ERR_IER, 0xffffffff); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci qm_fqalloc = devm_gen_pool_create(dev, 0, -1, "qman-fqalloc"); 86462306a36Sopenharmony_ci if (IS_ERR(qm_fqalloc)) { 86562306a36Sopenharmony_ci ret = PTR_ERR(qm_fqalloc); 86662306a36Sopenharmony_ci dev_err(dev, "qman-fqalloc pool init failed (%d)\n", ret); 86762306a36Sopenharmony_ci return ret; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci qm_qpalloc = devm_gen_pool_create(dev, 0, -1, "qman-qpalloc"); 87162306a36Sopenharmony_ci if (IS_ERR(qm_qpalloc)) { 87262306a36Sopenharmony_ci ret = PTR_ERR(qm_qpalloc); 87362306a36Sopenharmony_ci dev_err(dev, "qman-qpalloc pool init failed (%d)\n", ret); 87462306a36Sopenharmony_ci return ret; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci qm_cgralloc = devm_gen_pool_create(dev, 0, -1, "qman-cgralloc"); 87862306a36Sopenharmony_ci if (IS_ERR(qm_cgralloc)) { 87962306a36Sopenharmony_ci ret = PTR_ERR(qm_cgralloc); 88062306a36Sopenharmony_ci dev_err(dev, "qman-cgralloc pool init failed (%d)\n", ret); 88162306a36Sopenharmony_ci return ret; 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci ret = qman_resource_init(dev); 88562306a36Sopenharmony_ci if (ret) 88662306a36Sopenharmony_ci return ret; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci ret = qman_alloc_fq_table(qm_get_fqid_maxcnt()); 88962306a36Sopenharmony_ci if (ret) 89062306a36Sopenharmony_ci return ret; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci ret = qman_wq_alloc(); 89362306a36Sopenharmony_ci if (ret) 89462306a36Sopenharmony_ci return ret; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci __qman_probed = 1; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci return 0; 89962306a36Sopenharmony_ci} 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_cistatic const struct of_device_id fsl_qman_ids[] = { 90262306a36Sopenharmony_ci { 90362306a36Sopenharmony_ci .compatible = "fsl,qman", 90462306a36Sopenharmony_ci }, 90562306a36Sopenharmony_ci {} 90662306a36Sopenharmony_ci}; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_cistatic struct platform_driver fsl_qman_driver = { 90962306a36Sopenharmony_ci .driver = { 91062306a36Sopenharmony_ci .name = KBUILD_MODNAME, 91162306a36Sopenharmony_ci .of_match_table = fsl_qman_ids, 91262306a36Sopenharmony_ci .suppress_bind_attrs = true, 91362306a36Sopenharmony_ci }, 91462306a36Sopenharmony_ci .probe = fsl_qman_probe, 91562306a36Sopenharmony_ci}; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_cibuiltin_platform_driver(fsl_qman_driver); 918