12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 27aa1aa6eSZhao Qiang /* 37aa1aa6eSZhao Qiang * Copyright (C) 2006-2010 Freescale Semiconductor, Inc. All rights reserved. 47aa1aa6eSZhao Qiang * 57aa1aa6eSZhao Qiang * Authors: Shlomi Gridish <gridish@freescale.com> 67aa1aa6eSZhao Qiang * Li Yang <leoli@freescale.com> 77aa1aa6eSZhao Qiang * Based on cpm2_common.c from Dan Malek (dmalek@jlc.net) 87aa1aa6eSZhao Qiang * 97aa1aa6eSZhao Qiang * Description: 107aa1aa6eSZhao Qiang * General Purpose functions for the global management of the 117aa1aa6eSZhao Qiang * QUICC Engine (QE). 127aa1aa6eSZhao Qiang */ 13875f2aabSRasmus Villemoes #include <linux/bitmap.h> 147aa1aa6eSZhao Qiang #include <linux/errno.h> 157aa1aa6eSZhao Qiang #include <linux/sched.h> 167aa1aa6eSZhao Qiang #include <linux/kernel.h> 177aa1aa6eSZhao Qiang #include <linux/param.h> 187aa1aa6eSZhao Qiang #include <linux/string.h> 197aa1aa6eSZhao Qiang #include <linux/spinlock.h> 207aa1aa6eSZhao Qiang #include <linux/mm.h> 217aa1aa6eSZhao Qiang #include <linux/interrupt.h> 227aa1aa6eSZhao Qiang #include <linux/module.h> 237aa1aa6eSZhao Qiang #include <linux/delay.h> 247aa1aa6eSZhao Qiang #include <linux/ioport.h> 2558099685SRasmus Villemoes #include <linux/iopoll.h> 267aa1aa6eSZhao Qiang #include <linux/crc32.h> 277aa1aa6eSZhao Qiang #include <linux/mod_devicetable.h> 287aa1aa6eSZhao Qiang #include <linux/of_platform.h> 297aa1aa6eSZhao Qiang #include <soc/fsl/qe/immap_qe.h> 307aa1aa6eSZhao Qiang #include <soc/fsl/qe/qe.h> 317aa1aa6eSZhao Qiang 327aa1aa6eSZhao Qiang static void qe_snums_init(void); 337aa1aa6eSZhao Qiang static int qe_sdma_init(void); 347aa1aa6eSZhao Qiang 357aa1aa6eSZhao Qiang static DEFINE_SPINLOCK(qe_lock); 367aa1aa6eSZhao Qiang DEFINE_SPINLOCK(cmxgcr_lock); 377aa1aa6eSZhao Qiang EXPORT_SYMBOL(cmxgcr_lock); 387aa1aa6eSZhao Qiang 397aa1aa6eSZhao Qiang /* We allocate this here because it is used almost exclusively for 407aa1aa6eSZhao Qiang * the communication processor devices. 417aa1aa6eSZhao Qiang */ 427aa1aa6eSZhao Qiang struct qe_immap __iomem *qe_immr; 437aa1aa6eSZhao Qiang EXPORT_SYMBOL(qe_immr); 447aa1aa6eSZhao Qiang 45875f2aabSRasmus Villemoes static u8 snums[QE_NUM_OF_SNUM]; /* Dynamically allocated SNUMs */ 46875f2aabSRasmus Villemoes static DECLARE_BITMAP(snum_state, QE_NUM_OF_SNUM); 477aa1aa6eSZhao Qiang static unsigned int qe_num_of_snum; 487aa1aa6eSZhao Qiang 497aa1aa6eSZhao Qiang static phys_addr_t qebase = -1; 507aa1aa6eSZhao Qiang 51d7fc5963SRasmus Villemoes static struct device_node *qe_get_device_node(void) 52d7fc5963SRasmus Villemoes { 53d7fc5963SRasmus Villemoes struct device_node *qe; 54d7fc5963SRasmus Villemoes 55d7fc5963SRasmus Villemoes /* 56d7fc5963SRasmus Villemoes * Newer device trees have an "fsl,qe" compatible property for the QE 57d7fc5963SRasmus Villemoes * node, but we still need to support older device trees. 58d7fc5963SRasmus Villemoes */ 59d7fc5963SRasmus Villemoes qe = of_find_compatible_node(NULL, NULL, "fsl,qe"); 60d7fc5963SRasmus Villemoes if (qe) 61d7fc5963SRasmus Villemoes return qe; 62d7fc5963SRasmus Villemoes return of_find_node_by_type(NULL, "qe"); 63d7fc5963SRasmus Villemoes } 64d7fc5963SRasmus Villemoes 65b54ea82fSChristophe Leroy static phys_addr_t get_qe_base(void) 667aa1aa6eSZhao Qiang { 677aa1aa6eSZhao Qiang struct device_node *qe; 685066943aSZhao Qiang int ret; 695066943aSZhao Qiang struct resource res; 707aa1aa6eSZhao Qiang 717aa1aa6eSZhao Qiang if (qebase != -1) 727aa1aa6eSZhao Qiang return qebase; 737aa1aa6eSZhao Qiang 74d7fc5963SRasmus Villemoes qe = qe_get_device_node(); 757aa1aa6eSZhao Qiang if (!qe) 767aa1aa6eSZhao Qiang return qebase; 777aa1aa6eSZhao Qiang 785066943aSZhao Qiang ret = of_address_to_resource(qe, 0, &res); 795066943aSZhao Qiang if (!ret) 805066943aSZhao Qiang qebase = res.start; 817aa1aa6eSZhao Qiang of_node_put(qe); 827aa1aa6eSZhao Qiang 837aa1aa6eSZhao Qiang return qebase; 847aa1aa6eSZhao Qiang } 857aa1aa6eSZhao Qiang 867aa1aa6eSZhao Qiang void qe_reset(void) 877aa1aa6eSZhao Qiang { 887aa1aa6eSZhao Qiang if (qe_immr == NULL) 897aa1aa6eSZhao Qiang qe_immr = ioremap(get_qe_base(), QE_IMMAP_SIZE); 907aa1aa6eSZhao Qiang 917aa1aa6eSZhao Qiang qe_snums_init(); 927aa1aa6eSZhao Qiang 937aa1aa6eSZhao Qiang qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID, 947aa1aa6eSZhao Qiang QE_CR_PROTOCOL_UNSPECIFIED, 0); 957aa1aa6eSZhao Qiang 967aa1aa6eSZhao Qiang /* Reclaim the MURAM memory for our use. */ 977aa1aa6eSZhao Qiang qe_muram_init(); 987aa1aa6eSZhao Qiang 997aa1aa6eSZhao Qiang if (qe_sdma_init()) 1007aa1aa6eSZhao Qiang panic("sdma init failed!"); 1017aa1aa6eSZhao Qiang } 1027aa1aa6eSZhao Qiang 1037aa1aa6eSZhao Qiang int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input) 1047aa1aa6eSZhao Qiang { 1057aa1aa6eSZhao Qiang unsigned long flags; 1067aa1aa6eSZhao Qiang u8 mcn_shift = 0, dev_shift = 0; 10758099685SRasmus Villemoes u32 val; 10858099685SRasmus Villemoes int ret; 1097aa1aa6eSZhao Qiang 1107aa1aa6eSZhao Qiang spin_lock_irqsave(&qe_lock, flags); 1117aa1aa6eSZhao Qiang if (cmd == QE_RESET) { 11277d7676aSRasmus Villemoes qe_iowrite32be((u32)(cmd | QE_CR_FLG), &qe_immr->cp.cecr); 1137aa1aa6eSZhao Qiang } else { 1147aa1aa6eSZhao Qiang if (cmd == QE_ASSIGN_PAGE) { 1157aa1aa6eSZhao Qiang /* Here device is the SNUM, not sub-block */ 1167aa1aa6eSZhao Qiang dev_shift = QE_CR_SNUM_SHIFT; 1177aa1aa6eSZhao Qiang } else if (cmd == QE_ASSIGN_RISC) { 1187aa1aa6eSZhao Qiang /* Here device is the SNUM, and mcnProtocol is 1197aa1aa6eSZhao Qiang * e_QeCmdRiscAssignment value */ 1207aa1aa6eSZhao Qiang dev_shift = QE_CR_SNUM_SHIFT; 1217aa1aa6eSZhao Qiang mcn_shift = QE_CR_MCN_RISC_ASSIGN_SHIFT; 1227aa1aa6eSZhao Qiang } else { 1237aa1aa6eSZhao Qiang if (device == QE_CR_SUBBLOCK_USB) 1247aa1aa6eSZhao Qiang mcn_shift = QE_CR_MCN_USB_SHIFT; 1257aa1aa6eSZhao Qiang else 1267aa1aa6eSZhao Qiang mcn_shift = QE_CR_MCN_NORMAL_SHIFT; 1277aa1aa6eSZhao Qiang } 1287aa1aa6eSZhao Qiang 12977d7676aSRasmus Villemoes qe_iowrite32be(cmd_input, &qe_immr->cp.cecdr); 13077d7676aSRasmus Villemoes qe_iowrite32be((cmd | QE_CR_FLG | ((u32)device << dev_shift) | (u32)mcn_protocol << mcn_shift), 13177d7676aSRasmus Villemoes &qe_immr->cp.cecr); 1327aa1aa6eSZhao Qiang } 1337aa1aa6eSZhao Qiang 1347aa1aa6eSZhao Qiang /* wait for the QE_CR_FLG to clear */ 13558099685SRasmus Villemoes ret = readx_poll_timeout_atomic(qe_ioread32be, &qe_immr->cp.cecr, val, 13658099685SRasmus Villemoes (val & QE_CR_FLG) == 0, 0, 100); 13758099685SRasmus Villemoes /* On timeout, ret is -ETIMEDOUT, otherwise it will be 0. */ 1387aa1aa6eSZhao Qiang spin_unlock_irqrestore(&qe_lock, flags); 1397aa1aa6eSZhao Qiang 14058099685SRasmus Villemoes return ret == 0; 1417aa1aa6eSZhao Qiang } 1427aa1aa6eSZhao Qiang EXPORT_SYMBOL(qe_issue_cmd); 1437aa1aa6eSZhao Qiang 1447aa1aa6eSZhao Qiang /* Set a baud rate generator. This needs lots of work. There are 1457aa1aa6eSZhao Qiang * 16 BRGs, which can be connected to the QE channels or output 1467aa1aa6eSZhao Qiang * as clocks. The BRGs are in two different block of internal 1477aa1aa6eSZhao Qiang * memory mapped space. 1487aa1aa6eSZhao Qiang * The BRG clock is the QE clock divided by 2. 1497aa1aa6eSZhao Qiang * It was set up long ago during the initial boot phase and is 1507aa1aa6eSZhao Qiang * is given to us. 1517aa1aa6eSZhao Qiang * Baud rate clocks are zero-based in the driver code (as that maps 1527aa1aa6eSZhao Qiang * to port numbers). Documentation uses 1-based numbering. 1537aa1aa6eSZhao Qiang */ 1547aa1aa6eSZhao Qiang static unsigned int brg_clk = 0; 1557aa1aa6eSZhao Qiang 1562ccf80b7SValentin Longchamp #define CLK_GRAN (1000) 1572ccf80b7SValentin Longchamp #define CLK_GRAN_LIMIT (5) 1582ccf80b7SValentin Longchamp 1597aa1aa6eSZhao Qiang unsigned int qe_get_brg_clk(void) 1607aa1aa6eSZhao Qiang { 1617aa1aa6eSZhao Qiang struct device_node *qe; 162123ee6e9SRasmus Villemoes u32 brg; 1632ccf80b7SValentin Longchamp unsigned int mod; 1647aa1aa6eSZhao Qiang 1657aa1aa6eSZhao Qiang if (brg_clk) 1667aa1aa6eSZhao Qiang return brg_clk; 1677aa1aa6eSZhao Qiang 168d7fc5963SRasmus Villemoes qe = qe_get_device_node(); 1697aa1aa6eSZhao Qiang if (!qe) 1707aa1aa6eSZhao Qiang return brg_clk; 1717aa1aa6eSZhao Qiang 172123ee6e9SRasmus Villemoes if (!of_property_read_u32(qe, "brg-frequency", &brg)) 173123ee6e9SRasmus Villemoes brg_clk = brg; 1747aa1aa6eSZhao Qiang 1757aa1aa6eSZhao Qiang of_node_put(qe); 1767aa1aa6eSZhao Qiang 1772ccf80b7SValentin Longchamp /* round this if near to a multiple of CLK_GRAN */ 1782ccf80b7SValentin Longchamp mod = brg_clk % CLK_GRAN; 1792ccf80b7SValentin Longchamp if (mod) { 1802ccf80b7SValentin Longchamp if (mod < CLK_GRAN_LIMIT) 1812ccf80b7SValentin Longchamp brg_clk -= mod; 1822ccf80b7SValentin Longchamp else if (mod > (CLK_GRAN - CLK_GRAN_LIMIT)) 1832ccf80b7SValentin Longchamp brg_clk += CLK_GRAN - mod; 1842ccf80b7SValentin Longchamp } 1852ccf80b7SValentin Longchamp 1867aa1aa6eSZhao Qiang return brg_clk; 1877aa1aa6eSZhao Qiang } 1887aa1aa6eSZhao Qiang EXPORT_SYMBOL(qe_get_brg_clk); 1897aa1aa6eSZhao Qiang 190e5c5c8d2SValentin Longchamp #define PVR_VER_836x 0x8083 191e5c5c8d2SValentin Longchamp #define PVR_VER_832x 0x8084 192e5c5c8d2SValentin Longchamp 193df049d1fSRasmus Villemoes static bool qe_general4_errata(void) 194df049d1fSRasmus Villemoes { 195df049d1fSRasmus Villemoes #ifdef CONFIG_PPC32 196df049d1fSRasmus Villemoes return pvr_version_is(PVR_VER_836x) || pvr_version_is(PVR_VER_832x); 197df049d1fSRasmus Villemoes #endif 198df049d1fSRasmus Villemoes return false; 199df049d1fSRasmus Villemoes } 200df049d1fSRasmus Villemoes 2017aa1aa6eSZhao Qiang /* Program the BRG to the given sampling rate and multiplier 2027aa1aa6eSZhao Qiang * 2037aa1aa6eSZhao Qiang * @brg: the BRG, QE_BRG1 - QE_BRG16 2047aa1aa6eSZhao Qiang * @rate: the desired sampling rate 2057aa1aa6eSZhao Qiang * @multiplier: corresponds to the value programmed in GUMR_L[RDCR] or 2067aa1aa6eSZhao Qiang * GUMR_L[TDCR]. E.g., if this BRG is the RX clock, and GUMR_L[RDCR]=01, 2077aa1aa6eSZhao Qiang * then 'multiplier' should be 8. 2087aa1aa6eSZhao Qiang */ 2097aa1aa6eSZhao Qiang int qe_setbrg(enum qe_clock brg, unsigned int rate, unsigned int multiplier) 2107aa1aa6eSZhao Qiang { 2117aa1aa6eSZhao Qiang u32 divisor, tempval; 2127aa1aa6eSZhao Qiang u32 div16 = 0; 2137aa1aa6eSZhao Qiang 2147aa1aa6eSZhao Qiang if ((brg < QE_BRG1) || (brg > QE_BRG16)) 2157aa1aa6eSZhao Qiang return -EINVAL; 2167aa1aa6eSZhao Qiang 2177aa1aa6eSZhao Qiang divisor = qe_get_brg_clk() / (rate * multiplier); 2187aa1aa6eSZhao Qiang 2197aa1aa6eSZhao Qiang if (divisor > QE_BRGC_DIVISOR_MAX + 1) { 2207aa1aa6eSZhao Qiang div16 = QE_BRGC_DIV16; 2217aa1aa6eSZhao Qiang divisor /= 16; 2227aa1aa6eSZhao Qiang } 2237aa1aa6eSZhao Qiang 2247aa1aa6eSZhao Qiang /* Errata QE_General4, which affects some MPC832x and MPC836x SOCs, says 2257aa1aa6eSZhao Qiang that the BRG divisor must be even if you're not using divide-by-16 2267aa1aa6eSZhao Qiang mode. */ 227df049d1fSRasmus Villemoes if (qe_general4_errata()) 2287aa1aa6eSZhao Qiang if (!div16 && (divisor & 1) && (divisor > 3)) 2297aa1aa6eSZhao Qiang divisor++; 2307aa1aa6eSZhao Qiang 2317aa1aa6eSZhao Qiang tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | 2327aa1aa6eSZhao Qiang QE_BRGC_ENABLE | div16; 2337aa1aa6eSZhao Qiang 23477d7676aSRasmus Villemoes qe_iowrite32be(tempval, &qe_immr->brg.brgc[brg - QE_BRG1]); 2357aa1aa6eSZhao Qiang 2367aa1aa6eSZhao Qiang return 0; 2377aa1aa6eSZhao Qiang } 2387aa1aa6eSZhao Qiang EXPORT_SYMBOL(qe_setbrg); 2397aa1aa6eSZhao Qiang 2407aa1aa6eSZhao Qiang /* Convert a string to a QE clock source enum 2417aa1aa6eSZhao Qiang * 2427aa1aa6eSZhao Qiang * This function takes a string, typically from a property in the device 2437aa1aa6eSZhao Qiang * tree, and returns the corresponding "enum qe_clock" value. 2447aa1aa6eSZhao Qiang */ 2457aa1aa6eSZhao Qiang enum qe_clock qe_clock_source(const char *source) 2467aa1aa6eSZhao Qiang { 2477aa1aa6eSZhao Qiang unsigned int i; 2487aa1aa6eSZhao Qiang 2497aa1aa6eSZhao Qiang if (strcasecmp(source, "none") == 0) 2507aa1aa6eSZhao Qiang return QE_CLK_NONE; 2517aa1aa6eSZhao Qiang 25268f047e3SZhao Qiang if (strcmp(source, "tsync_pin") == 0) 25368f047e3SZhao Qiang return QE_TSYNC_PIN; 25468f047e3SZhao Qiang 25568f047e3SZhao Qiang if (strcmp(source, "rsync_pin") == 0) 25668f047e3SZhao Qiang return QE_RSYNC_PIN; 25768f047e3SZhao Qiang 2587aa1aa6eSZhao Qiang if (strncasecmp(source, "brg", 3) == 0) { 2597aa1aa6eSZhao Qiang i = simple_strtoul(source + 3, NULL, 10); 2607aa1aa6eSZhao Qiang if ((i >= 1) && (i <= 16)) 2617aa1aa6eSZhao Qiang return (QE_BRG1 - 1) + i; 2627aa1aa6eSZhao Qiang else 2637aa1aa6eSZhao Qiang return QE_CLK_DUMMY; 2647aa1aa6eSZhao Qiang } 2657aa1aa6eSZhao Qiang 2667aa1aa6eSZhao Qiang if (strncasecmp(source, "clk", 3) == 0) { 2677aa1aa6eSZhao Qiang i = simple_strtoul(source + 3, NULL, 10); 2687aa1aa6eSZhao Qiang if ((i >= 1) && (i <= 24)) 2697aa1aa6eSZhao Qiang return (QE_CLK1 - 1) + i; 2707aa1aa6eSZhao Qiang else 2717aa1aa6eSZhao Qiang return QE_CLK_DUMMY; 2727aa1aa6eSZhao Qiang } 2737aa1aa6eSZhao Qiang 2747aa1aa6eSZhao Qiang return QE_CLK_DUMMY; 2757aa1aa6eSZhao Qiang } 2767aa1aa6eSZhao Qiang EXPORT_SYMBOL(qe_clock_source); 2777aa1aa6eSZhao Qiang 2787aa1aa6eSZhao Qiang /* Initialize SNUMs (thread serial numbers) according to 2797aa1aa6eSZhao Qiang * QE Module Control chapter, SNUM table 2807aa1aa6eSZhao Qiang */ 2817aa1aa6eSZhao Qiang static void qe_snums_init(void) 2827aa1aa6eSZhao Qiang { 2837aa1aa6eSZhao Qiang static const u8 snum_init_76[] = { 2847aa1aa6eSZhao Qiang 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D, 2857aa1aa6eSZhao Qiang 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89, 2867aa1aa6eSZhao Qiang 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9, 2877aa1aa6eSZhao Qiang 0xD8, 0xD9, 0xE8, 0xE9, 0x44, 0x45, 0x4C, 0x4D, 2887aa1aa6eSZhao Qiang 0x54, 0x55, 0x5C, 0x5D, 0x64, 0x65, 0x6C, 0x6D, 2897aa1aa6eSZhao Qiang 0x74, 0x75, 0x7C, 0x7D, 0x84, 0x85, 0x8C, 0x8D, 2907aa1aa6eSZhao Qiang 0x94, 0x95, 0x9C, 0x9D, 0xA4, 0xA5, 0xAC, 0xAD, 2917aa1aa6eSZhao Qiang 0xB4, 0xB5, 0xBC, 0xBD, 0xC4, 0xC5, 0xCC, 0xCD, 2927aa1aa6eSZhao Qiang 0xD4, 0xD5, 0xDC, 0xDD, 0xE4, 0xE5, 0xEC, 0xED, 2937aa1aa6eSZhao Qiang 0xF4, 0xF5, 0xFC, 0xFD, 2947aa1aa6eSZhao Qiang }; 2957aa1aa6eSZhao Qiang static const u8 snum_init_46[] = { 2967aa1aa6eSZhao Qiang 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D, 2977aa1aa6eSZhao Qiang 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89, 2987aa1aa6eSZhao Qiang 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9, 2997aa1aa6eSZhao Qiang 0xD8, 0xD9, 0xE8, 0xE9, 0x08, 0x09, 0x18, 0x19, 3007aa1aa6eSZhao Qiang 0x28, 0x29, 0x38, 0x39, 0x48, 0x49, 0x58, 0x59, 3017aa1aa6eSZhao Qiang 0x68, 0x69, 0x78, 0x79, 0x80, 0x81, 3027aa1aa6eSZhao Qiang }; 3035cfca891SRasmus Villemoes struct device_node *qe; 304f03de74dSRasmus Villemoes const u8 *snum_init; 3055cfca891SRasmus Villemoes int i; 3067aa1aa6eSZhao Qiang 3075cfca891SRasmus Villemoes bitmap_zero(snum_state, QE_NUM_OF_SNUM); 30821560067SRasmus Villemoes qe_num_of_snum = 28; /* The default number of snum for threads is 28 */ 3095cfca891SRasmus Villemoes qe = qe_get_device_node(); 3105cfca891SRasmus Villemoes if (qe) { 3115cfca891SRasmus Villemoes i = of_property_read_variable_u8_array(qe, "fsl,qe-snums", 3125cfca891SRasmus Villemoes snums, 1, QE_NUM_OF_SNUM); 3135cfca891SRasmus Villemoes if (i > 0) { 31421560067SRasmus Villemoes of_node_put(qe); 3155cfca891SRasmus Villemoes qe_num_of_snum = i; 3165cfca891SRasmus Villemoes return; 3177aa1aa6eSZhao Qiang } 31821560067SRasmus Villemoes /* 31921560067SRasmus Villemoes * Fall back to legacy binding of using the value of 32021560067SRasmus Villemoes * fsl,qe-num-snums to choose one of the static arrays 32121560067SRasmus Villemoes * above. 32221560067SRasmus Villemoes */ 32321560067SRasmus Villemoes of_property_read_u32(qe, "fsl,qe-num-snums", &qe_num_of_snum); 32421560067SRasmus Villemoes of_node_put(qe); 3255cfca891SRasmus Villemoes } 3267aa1aa6eSZhao Qiang 32721560067SRasmus Villemoes if (qe_num_of_snum == 76) { 3287aa1aa6eSZhao Qiang snum_init = snum_init_76; 32921560067SRasmus Villemoes } else if (qe_num_of_snum == 28 || qe_num_of_snum == 46) { 3307aa1aa6eSZhao Qiang snum_init = snum_init_46; 33121560067SRasmus Villemoes } else { 33221560067SRasmus Villemoes pr_err("QE: unsupported value of fsl,qe-num-snums: %u\n", qe_num_of_snum); 33321560067SRasmus Villemoes return; 33421560067SRasmus Villemoes } 335875f2aabSRasmus Villemoes memcpy(snums, snum_init, qe_num_of_snum); 3367aa1aa6eSZhao Qiang } 3377aa1aa6eSZhao Qiang 3387aa1aa6eSZhao Qiang int qe_get_snum(void) 3397aa1aa6eSZhao Qiang { 3407aa1aa6eSZhao Qiang unsigned long flags; 3417aa1aa6eSZhao Qiang int snum = -EBUSY; 3427aa1aa6eSZhao Qiang int i; 3437aa1aa6eSZhao Qiang 3447aa1aa6eSZhao Qiang spin_lock_irqsave(&qe_lock, flags); 345875f2aabSRasmus Villemoes i = find_first_zero_bit(snum_state, qe_num_of_snum); 346875f2aabSRasmus Villemoes if (i < qe_num_of_snum) { 347875f2aabSRasmus Villemoes set_bit(i, snum_state); 348875f2aabSRasmus Villemoes snum = snums[i]; 3497aa1aa6eSZhao Qiang } 3507aa1aa6eSZhao Qiang spin_unlock_irqrestore(&qe_lock, flags); 3517aa1aa6eSZhao Qiang 3527aa1aa6eSZhao Qiang return snum; 3537aa1aa6eSZhao Qiang } 3547aa1aa6eSZhao Qiang EXPORT_SYMBOL(qe_get_snum); 3557aa1aa6eSZhao Qiang 3567aa1aa6eSZhao Qiang void qe_put_snum(u8 snum) 3577aa1aa6eSZhao Qiang { 358875f2aabSRasmus Villemoes const u8 *p = memchr(snums, snum, qe_num_of_snum); 3597aa1aa6eSZhao Qiang 360875f2aabSRasmus Villemoes if (p) 361875f2aabSRasmus Villemoes clear_bit(p - snums, snum_state); 3627aa1aa6eSZhao Qiang } 3637aa1aa6eSZhao Qiang EXPORT_SYMBOL(qe_put_snum); 3647aa1aa6eSZhao Qiang 3657aa1aa6eSZhao Qiang static int qe_sdma_init(void) 3667aa1aa6eSZhao Qiang { 3677aa1aa6eSZhao Qiang struct sdma __iomem *sdma = &qe_immr->sdma; 3684c3e565cSRasmus Villemoes static s32 sdma_buf_offset = -ENOMEM; 3697aa1aa6eSZhao Qiang 3707aa1aa6eSZhao Qiang if (!sdma) 3717aa1aa6eSZhao Qiang return -ENODEV; 3727aa1aa6eSZhao Qiang 3737aa1aa6eSZhao Qiang /* allocate 2 internal temporary buffers (512 bytes size each) for 3747aa1aa6eSZhao Qiang * the SDMA */ 3754c3e565cSRasmus Villemoes if (sdma_buf_offset < 0) { 3767aa1aa6eSZhao Qiang sdma_buf_offset = qe_muram_alloc(512 * 2, 4096); 3774c3e565cSRasmus Villemoes if (sdma_buf_offset < 0) 3787aa1aa6eSZhao Qiang return -ENOMEM; 3797aa1aa6eSZhao Qiang } 3807aa1aa6eSZhao Qiang 38177d7676aSRasmus Villemoes qe_iowrite32be((u32)sdma_buf_offset & QE_SDEBCR_BA_MASK, 38277d7676aSRasmus Villemoes &sdma->sdebcr); 38377d7676aSRasmus Villemoes qe_iowrite32be((QE_SDMR_GLB_1_MSK | (0x1 << QE_SDMR_CEN_SHIFT)), 38477d7676aSRasmus Villemoes &sdma->sdmr); 3857aa1aa6eSZhao Qiang 3867aa1aa6eSZhao Qiang return 0; 3877aa1aa6eSZhao Qiang } 3887aa1aa6eSZhao Qiang 3897aa1aa6eSZhao Qiang /* The maximum number of RISCs we support */ 3907aa1aa6eSZhao Qiang #define MAX_QE_RISC 4 3917aa1aa6eSZhao Qiang 3927aa1aa6eSZhao Qiang /* Firmware information stored here for qe_get_firmware_info() */ 3937aa1aa6eSZhao Qiang static struct qe_firmware_info qe_firmware_info; 3947aa1aa6eSZhao Qiang 3957aa1aa6eSZhao Qiang /* 3967aa1aa6eSZhao Qiang * Set to 1 if QE firmware has been uploaded, and therefore 3977aa1aa6eSZhao Qiang * qe_firmware_info contains valid data. 3987aa1aa6eSZhao Qiang */ 3997aa1aa6eSZhao Qiang static int qe_firmware_uploaded; 4007aa1aa6eSZhao Qiang 4017aa1aa6eSZhao Qiang /* 4027aa1aa6eSZhao Qiang * Upload a QE microcode 4037aa1aa6eSZhao Qiang * 4047aa1aa6eSZhao Qiang * This function is a worker function for qe_upload_firmware(). It does 4057aa1aa6eSZhao Qiang * the actual uploading of the microcode. 4067aa1aa6eSZhao Qiang */ 4077aa1aa6eSZhao Qiang static void qe_upload_microcode(const void *base, 4087aa1aa6eSZhao Qiang const struct qe_microcode *ucode) 4097aa1aa6eSZhao Qiang { 4107aa1aa6eSZhao Qiang const __be32 *code = base + be32_to_cpu(ucode->code_offset); 4117aa1aa6eSZhao Qiang unsigned int i; 4127aa1aa6eSZhao Qiang 4137aa1aa6eSZhao Qiang if (ucode->major || ucode->minor || ucode->revision) 4147aa1aa6eSZhao Qiang printk(KERN_INFO "qe-firmware: " 4157aa1aa6eSZhao Qiang "uploading microcode '%s' version %u.%u.%u\n", 4167aa1aa6eSZhao Qiang ucode->id, ucode->major, ucode->minor, ucode->revision); 4177aa1aa6eSZhao Qiang else 4187aa1aa6eSZhao Qiang printk(KERN_INFO "qe-firmware: " 4197aa1aa6eSZhao Qiang "uploading microcode '%s'\n", ucode->id); 4207aa1aa6eSZhao Qiang 4217aa1aa6eSZhao Qiang /* Use auto-increment */ 42277d7676aSRasmus Villemoes qe_iowrite32be(be32_to_cpu(ucode->iram_offset) | QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR, 42377d7676aSRasmus Villemoes &qe_immr->iram.iadd); 4247aa1aa6eSZhao Qiang 4257aa1aa6eSZhao Qiang for (i = 0; i < be32_to_cpu(ucode->count); i++) 42677d7676aSRasmus Villemoes qe_iowrite32be(be32_to_cpu(code[i]), &qe_immr->iram.idata); 4277aa1aa6eSZhao Qiang 4287aa1aa6eSZhao Qiang /* Set I-RAM Ready Register */ 42977d7676aSRasmus Villemoes qe_iowrite32be(be32_to_cpu(QE_IRAM_READY), &qe_immr->iram.iready); 4307aa1aa6eSZhao Qiang } 4317aa1aa6eSZhao Qiang 4327aa1aa6eSZhao Qiang /* 4337aa1aa6eSZhao Qiang * Upload a microcode to the I-RAM at a specific address. 4347aa1aa6eSZhao Qiang * 4354d2e26a3SMauro Carvalho Chehab * See Documentation/powerpc/qe_firmware.rst for information on QE microcode 4367aa1aa6eSZhao Qiang * uploading. 4377aa1aa6eSZhao Qiang * 4387aa1aa6eSZhao Qiang * Currently, only version 1 is supported, so the 'version' field must be 4397aa1aa6eSZhao Qiang * set to 1. 4407aa1aa6eSZhao Qiang * 4417aa1aa6eSZhao Qiang * The SOC model and revision are not validated, they are only displayed for 4427aa1aa6eSZhao Qiang * informational purposes. 4437aa1aa6eSZhao Qiang * 4447aa1aa6eSZhao Qiang * 'calc_size' is the calculated size, in bytes, of the firmware structure and 4457aa1aa6eSZhao Qiang * all of the microcode structures, minus the CRC. 4467aa1aa6eSZhao Qiang * 4477aa1aa6eSZhao Qiang * 'length' is the size that the structure says it is, including the CRC. 4487aa1aa6eSZhao Qiang */ 4497aa1aa6eSZhao Qiang int qe_upload_firmware(const struct qe_firmware *firmware) 4507aa1aa6eSZhao Qiang { 4517aa1aa6eSZhao Qiang unsigned int i; 4527aa1aa6eSZhao Qiang unsigned int j; 4537aa1aa6eSZhao Qiang u32 crc; 4547aa1aa6eSZhao Qiang size_t calc_size = sizeof(struct qe_firmware); 4557aa1aa6eSZhao Qiang size_t length; 4567aa1aa6eSZhao Qiang const struct qe_header *hdr; 4577aa1aa6eSZhao Qiang 4587aa1aa6eSZhao Qiang if (!firmware) { 4597aa1aa6eSZhao Qiang printk(KERN_ERR "qe-firmware: invalid pointer\n"); 4607aa1aa6eSZhao Qiang return -EINVAL; 4617aa1aa6eSZhao Qiang } 4627aa1aa6eSZhao Qiang 4637aa1aa6eSZhao Qiang hdr = &firmware->header; 4647aa1aa6eSZhao Qiang length = be32_to_cpu(hdr->length); 4657aa1aa6eSZhao Qiang 4667aa1aa6eSZhao Qiang /* Check the magic */ 4677aa1aa6eSZhao Qiang if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') || 4687aa1aa6eSZhao Qiang (hdr->magic[2] != 'F')) { 4697aa1aa6eSZhao Qiang printk(KERN_ERR "qe-firmware: not a microcode\n"); 4707aa1aa6eSZhao Qiang return -EPERM; 4717aa1aa6eSZhao Qiang } 4727aa1aa6eSZhao Qiang 4737aa1aa6eSZhao Qiang /* Check the version */ 4747aa1aa6eSZhao Qiang if (hdr->version != 1) { 4757aa1aa6eSZhao Qiang printk(KERN_ERR "qe-firmware: unsupported version\n"); 4767aa1aa6eSZhao Qiang return -EPERM; 4777aa1aa6eSZhao Qiang } 4787aa1aa6eSZhao Qiang 4797aa1aa6eSZhao Qiang /* Validate some of the fields */ 4807aa1aa6eSZhao Qiang if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) { 4817aa1aa6eSZhao Qiang printk(KERN_ERR "qe-firmware: invalid data\n"); 4827aa1aa6eSZhao Qiang return -EINVAL; 4837aa1aa6eSZhao Qiang } 4847aa1aa6eSZhao Qiang 4857aa1aa6eSZhao Qiang /* Validate the length and check if there's a CRC */ 4867aa1aa6eSZhao Qiang calc_size += (firmware->count - 1) * sizeof(struct qe_microcode); 4877aa1aa6eSZhao Qiang 4887aa1aa6eSZhao Qiang for (i = 0; i < firmware->count; i++) 4897aa1aa6eSZhao Qiang /* 4907aa1aa6eSZhao Qiang * For situations where the second RISC uses the same microcode 4917aa1aa6eSZhao Qiang * as the first, the 'code_offset' and 'count' fields will be 4927aa1aa6eSZhao Qiang * zero, so it's okay to add those. 4937aa1aa6eSZhao Qiang */ 4947aa1aa6eSZhao Qiang calc_size += sizeof(__be32) * 4957aa1aa6eSZhao Qiang be32_to_cpu(firmware->microcode[i].count); 4967aa1aa6eSZhao Qiang 4977aa1aa6eSZhao Qiang /* Validate the length */ 4987aa1aa6eSZhao Qiang if (length != calc_size + sizeof(__be32)) { 4997aa1aa6eSZhao Qiang printk(KERN_ERR "qe-firmware: invalid length\n"); 5007aa1aa6eSZhao Qiang return -EPERM; 5017aa1aa6eSZhao Qiang } 5027aa1aa6eSZhao Qiang 5037aa1aa6eSZhao Qiang /* Validate the CRC */ 5047aa1aa6eSZhao Qiang crc = be32_to_cpu(*(__be32 *)((void *)firmware + calc_size)); 5057aa1aa6eSZhao Qiang if (crc != crc32(0, firmware, calc_size)) { 5067aa1aa6eSZhao Qiang printk(KERN_ERR "qe-firmware: firmware CRC is invalid\n"); 5077aa1aa6eSZhao Qiang return -EIO; 5087aa1aa6eSZhao Qiang } 5097aa1aa6eSZhao Qiang 5107aa1aa6eSZhao Qiang /* 5117aa1aa6eSZhao Qiang * If the microcode calls for it, split the I-RAM. 5127aa1aa6eSZhao Qiang */ 5137aa1aa6eSZhao Qiang if (!firmware->split) 51477d7676aSRasmus Villemoes qe_setbits_be16(&qe_immr->cp.cercr, QE_CP_CERCR_CIR); 5157aa1aa6eSZhao Qiang 5167aa1aa6eSZhao Qiang if (firmware->soc.model) 5177aa1aa6eSZhao Qiang printk(KERN_INFO 5187aa1aa6eSZhao Qiang "qe-firmware: firmware '%s' for %u V%u.%u\n", 5197aa1aa6eSZhao Qiang firmware->id, be16_to_cpu(firmware->soc.model), 5207aa1aa6eSZhao Qiang firmware->soc.major, firmware->soc.minor); 5217aa1aa6eSZhao Qiang else 5227aa1aa6eSZhao Qiang printk(KERN_INFO "qe-firmware: firmware '%s'\n", 5237aa1aa6eSZhao Qiang firmware->id); 5247aa1aa6eSZhao Qiang 5257aa1aa6eSZhao Qiang /* 5267aa1aa6eSZhao Qiang * The QE only supports one microcode per RISC, so clear out all the 5277aa1aa6eSZhao Qiang * saved microcode information and put in the new. 5287aa1aa6eSZhao Qiang */ 5297aa1aa6eSZhao Qiang memset(&qe_firmware_info, 0, sizeof(qe_firmware_info)); 5307aa1aa6eSZhao Qiang strlcpy(qe_firmware_info.id, firmware->id, sizeof(qe_firmware_info.id)); 5317aa1aa6eSZhao Qiang qe_firmware_info.extended_modes = firmware->extended_modes; 5327aa1aa6eSZhao Qiang memcpy(qe_firmware_info.vtraps, firmware->vtraps, 5337aa1aa6eSZhao Qiang sizeof(firmware->vtraps)); 5347aa1aa6eSZhao Qiang 5357aa1aa6eSZhao Qiang /* Loop through each microcode. */ 5367aa1aa6eSZhao Qiang for (i = 0; i < firmware->count; i++) { 5377aa1aa6eSZhao Qiang const struct qe_microcode *ucode = &firmware->microcode[i]; 5387aa1aa6eSZhao Qiang 5397aa1aa6eSZhao Qiang /* Upload a microcode if it's present */ 5407aa1aa6eSZhao Qiang if (ucode->code_offset) 5417aa1aa6eSZhao Qiang qe_upload_microcode(firmware, ucode); 5427aa1aa6eSZhao Qiang 5437aa1aa6eSZhao Qiang /* Program the traps for this processor */ 5447aa1aa6eSZhao Qiang for (j = 0; j < 16; j++) { 5457aa1aa6eSZhao Qiang u32 trap = be32_to_cpu(ucode->traps[j]); 5467aa1aa6eSZhao Qiang 5477aa1aa6eSZhao Qiang if (trap) 54877d7676aSRasmus Villemoes qe_iowrite32be(trap, 54977d7676aSRasmus Villemoes &qe_immr->rsp[i].tibcr[j]); 5507aa1aa6eSZhao Qiang } 5517aa1aa6eSZhao Qiang 5527aa1aa6eSZhao Qiang /* Enable traps */ 55377d7676aSRasmus Villemoes qe_iowrite32be(be32_to_cpu(ucode->eccr), 55477d7676aSRasmus Villemoes &qe_immr->rsp[i].eccr); 5557aa1aa6eSZhao Qiang } 5567aa1aa6eSZhao Qiang 5577aa1aa6eSZhao Qiang qe_firmware_uploaded = 1; 5587aa1aa6eSZhao Qiang 5597aa1aa6eSZhao Qiang return 0; 5607aa1aa6eSZhao Qiang } 5617aa1aa6eSZhao Qiang EXPORT_SYMBOL(qe_upload_firmware); 5627aa1aa6eSZhao Qiang 5637aa1aa6eSZhao Qiang /* 5647aa1aa6eSZhao Qiang * Get info on the currently-loaded firmware 5657aa1aa6eSZhao Qiang * 5667aa1aa6eSZhao Qiang * This function also checks the device tree to see if the boot loader has 5677aa1aa6eSZhao Qiang * uploaded a firmware already. 5687aa1aa6eSZhao Qiang */ 5697aa1aa6eSZhao Qiang struct qe_firmware_info *qe_get_firmware_info(void) 5707aa1aa6eSZhao Qiang { 5717aa1aa6eSZhao Qiang static int initialized; 5727aa1aa6eSZhao Qiang struct device_node *qe; 5737aa1aa6eSZhao Qiang struct device_node *fw = NULL; 5747aa1aa6eSZhao Qiang const char *sprop; 5757aa1aa6eSZhao Qiang 5767aa1aa6eSZhao Qiang /* 5777aa1aa6eSZhao Qiang * If we haven't checked yet, and a driver hasn't uploaded a firmware 5787aa1aa6eSZhao Qiang * yet, then check the device tree for information. 5797aa1aa6eSZhao Qiang */ 5807aa1aa6eSZhao Qiang if (qe_firmware_uploaded) 5817aa1aa6eSZhao Qiang return &qe_firmware_info; 5827aa1aa6eSZhao Qiang 5837aa1aa6eSZhao Qiang if (initialized) 5847aa1aa6eSZhao Qiang return NULL; 5857aa1aa6eSZhao Qiang 5867aa1aa6eSZhao Qiang initialized = 1; 5877aa1aa6eSZhao Qiang 588d7fc5963SRasmus Villemoes qe = qe_get_device_node(); 5897aa1aa6eSZhao Qiang if (!qe) 5907aa1aa6eSZhao Qiang return NULL; 5917aa1aa6eSZhao Qiang 5927aa1aa6eSZhao Qiang /* Find the 'firmware' child node */ 593f55f6122SRob Herring fw = of_get_child_by_name(qe, "firmware"); 5947aa1aa6eSZhao Qiang of_node_put(qe); 5957aa1aa6eSZhao Qiang 5967aa1aa6eSZhao Qiang /* Did we find the 'firmware' node? */ 5977aa1aa6eSZhao Qiang if (!fw) 5987aa1aa6eSZhao Qiang return NULL; 5997aa1aa6eSZhao Qiang 6007aa1aa6eSZhao Qiang qe_firmware_uploaded = 1; 6017aa1aa6eSZhao Qiang 6027aa1aa6eSZhao Qiang /* Copy the data into qe_firmware_info*/ 6037aa1aa6eSZhao Qiang sprop = of_get_property(fw, "id", NULL); 6047aa1aa6eSZhao Qiang if (sprop) 6057aa1aa6eSZhao Qiang strlcpy(qe_firmware_info.id, sprop, 6067aa1aa6eSZhao Qiang sizeof(qe_firmware_info.id)); 6077aa1aa6eSZhao Qiang 608123ee6e9SRasmus Villemoes of_property_read_u64(fw, "extended-modes", 609123ee6e9SRasmus Villemoes &qe_firmware_info.extended_modes); 6107aa1aa6eSZhao Qiang 611123ee6e9SRasmus Villemoes of_property_read_u32_array(fw, "virtual-traps", qe_firmware_info.vtraps, 612123ee6e9SRasmus Villemoes ARRAY_SIZE(qe_firmware_info.vtraps)); 6137aa1aa6eSZhao Qiang 6147aa1aa6eSZhao Qiang of_node_put(fw); 6157aa1aa6eSZhao Qiang 6167aa1aa6eSZhao Qiang return &qe_firmware_info; 6177aa1aa6eSZhao Qiang } 6187aa1aa6eSZhao Qiang EXPORT_SYMBOL(qe_get_firmware_info); 6197aa1aa6eSZhao Qiang 6207aa1aa6eSZhao Qiang unsigned int qe_get_num_of_risc(void) 6217aa1aa6eSZhao Qiang { 6227aa1aa6eSZhao Qiang struct device_node *qe; 6237aa1aa6eSZhao Qiang unsigned int num_of_risc = 0; 6247aa1aa6eSZhao Qiang 625d7fc5963SRasmus Villemoes qe = qe_get_device_node(); 6267aa1aa6eSZhao Qiang if (!qe) 6277aa1aa6eSZhao Qiang return num_of_risc; 6287aa1aa6eSZhao Qiang 629123ee6e9SRasmus Villemoes of_property_read_u32(qe, "fsl,qe-num-riscs", &num_of_risc); 6307aa1aa6eSZhao Qiang 6317aa1aa6eSZhao Qiang of_node_put(qe); 6327aa1aa6eSZhao Qiang 6337aa1aa6eSZhao Qiang return num_of_risc; 6347aa1aa6eSZhao Qiang } 6357aa1aa6eSZhao Qiang EXPORT_SYMBOL(qe_get_num_of_risc); 6367aa1aa6eSZhao Qiang 6377aa1aa6eSZhao Qiang unsigned int qe_get_num_of_snums(void) 6387aa1aa6eSZhao Qiang { 63921560067SRasmus Villemoes return qe_num_of_snum; 6407aa1aa6eSZhao Qiang } 6417aa1aa6eSZhao Qiang EXPORT_SYMBOL(qe_get_num_of_snums); 6427aa1aa6eSZhao Qiang 6437aa1aa6eSZhao Qiang static int __init qe_init(void) 6447aa1aa6eSZhao Qiang { 6457aa1aa6eSZhao Qiang struct device_node *np; 6467aa1aa6eSZhao Qiang 6477aa1aa6eSZhao Qiang np = of_find_compatible_node(NULL, NULL, "fsl,qe"); 6487aa1aa6eSZhao Qiang if (!np) 6497aa1aa6eSZhao Qiang return -ENODEV; 6507aa1aa6eSZhao Qiang qe_reset(); 6517aa1aa6eSZhao Qiang of_node_put(np); 6527aa1aa6eSZhao Qiang return 0; 6537aa1aa6eSZhao Qiang } 6547aa1aa6eSZhao Qiang subsys_initcall(qe_init); 6557aa1aa6eSZhao Qiang 6567aa1aa6eSZhao Qiang #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx) 6577aa1aa6eSZhao Qiang static int qe_resume(struct platform_device *ofdev) 6587aa1aa6eSZhao Qiang { 6597aa1aa6eSZhao Qiang if (!qe_alive_during_sleep()) 6607aa1aa6eSZhao Qiang qe_reset(); 6617aa1aa6eSZhao Qiang return 0; 6627aa1aa6eSZhao Qiang } 6637aa1aa6eSZhao Qiang 6647aa1aa6eSZhao Qiang static int qe_probe(struct platform_device *ofdev) 6657aa1aa6eSZhao Qiang { 6667aa1aa6eSZhao Qiang return 0; 6677aa1aa6eSZhao Qiang } 6687aa1aa6eSZhao Qiang 6697aa1aa6eSZhao Qiang static const struct of_device_id qe_ids[] = { 6707aa1aa6eSZhao Qiang { .compatible = "fsl,qe", }, 6717aa1aa6eSZhao Qiang { }, 6727aa1aa6eSZhao Qiang }; 6737aa1aa6eSZhao Qiang 6747aa1aa6eSZhao Qiang static struct platform_driver qe_driver = { 6757aa1aa6eSZhao Qiang .driver = { 6767aa1aa6eSZhao Qiang .name = "fsl-qe", 6777aa1aa6eSZhao Qiang .of_match_table = qe_ids, 6787aa1aa6eSZhao Qiang }, 6797aa1aa6eSZhao Qiang .probe = qe_probe, 6807aa1aa6eSZhao Qiang .resume = qe_resume, 6817aa1aa6eSZhao Qiang }; 6827aa1aa6eSZhao Qiang 683c9492b4bSGeliang Tang builtin_platform_driver(qe_driver); 6847aa1aa6eSZhao Qiang #endif /* defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx) */ 685