uboot/drivers/net/fsl-mc/dpio/qbman_sys.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0+ */
   2/*
   3 * Copyright (C) 2014 Freescale Semiconductor
   4 */
   5
   6/* qbman_sys_decl.h and qbman_sys.h are the two platform-specific files in the
   7 * driver. They are only included via qbman_private.h, which is itself a
   8 * platform-independent file and is included by all the other driver source.
   9 *
  10 * qbman_sys_decl.h is included prior to all other declarations and logic, and
  11 * it exists to provide compatibility with any linux interfaces our
  12 * single-source driver code is dependent on (eg. kmalloc). Ie. this file
  13 * provides linux compatibility.
  14 *
  15 * This qbman_sys.h header, on the other hand, is included *after* any common
  16 * and platform-neutral declarations and logic in qbman_private.h, and exists to
  17 * implement any platform-specific logic of the qbman driver itself. Ie. it is
  18 * *not* to provide linux compatibility.
  19 */
  20
  21/* Trace the 3 different classes of read/write access to QBMan. #undef as
  22 * required. */
  23#include <linux/bug.h>
  24#undef QBMAN_CCSR_TRACE
  25#undef QBMAN_CINH_TRACE
  26#undef QBMAN_CENA_TRACE
  27
  28/* Temporarily define this to get around the fact that cache enabled mapping is
  29 * not working right now. Will remove this after uboot could map the cache
  30 * enabled portal memory.
  31 */
  32#define QBMAN_CINH_ONLY
  33
  34static inline void word_copy(void *d, const void *s, unsigned int cnt)
  35{
  36        uint32_t *dd = d;
  37        const uint32_t *ss = s;
  38
  39        while (cnt--)
  40                *(dd++) = *(ss++);
  41}
  42
  43/* Currently, the CENA support code expects each 32-bit word to be written in
  44 * host order, and these are converted to hardware (little-endian) order on
  45 * command submission. However, 64-bit quantities are must be written (and read)
  46 * as two 32-bit words with the least-significant word first, irrespective of
  47 * host endianness. */
  48static inline void u64_to_le32_copy(void *d, const uint64_t *s,
  49                                        unsigned int cnt)
  50{
  51        uint32_t *dd = d;
  52        const uint32_t *ss = (const uint32_t *)s;
  53
  54        while (cnt--) {
  55                /* TBD: the toolchain was choking on the use of 64-bit types up
  56                 * until recently so this works entirely with 32-bit variables.
  57                 * When 64-bit types become usable again, investigate better
  58                 * ways of doing this. */
  59#if defined(__BIG_ENDIAN)
  60                *(dd++) = ss[1];
  61                *(dd++) = ss[0];
  62                ss += 2;
  63#else
  64                *(dd++) = *(ss++);
  65                *(dd++) = *(ss++);
  66#endif
  67        }
  68}
  69static inline void u64_from_le32_copy(uint64_t *d, const void *s,
  70                                        unsigned int cnt)
  71{
  72        const uint32_t *ss = s;
  73        uint32_t *dd = (uint32_t *)d;
  74
  75        while (cnt--) {
  76#if defined(__BIG_ENDIAN)
  77                dd[1] = *(ss++);
  78                dd[0] = *(ss++);
  79                dd += 2;
  80#else
  81                *(dd++) = *(ss++);
  82                *(dd++) = *(ss++);
  83#endif
  84        }
  85}
  86
  87/* Convert a host-native 32bit value into little endian */
  88#if defined(__BIG_ENDIAN)
  89static inline uint32_t make_le32(uint32_t val)
  90{
  91        return ((val & 0xff) << 24) | ((val & 0xff00) << 8) |
  92                ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24);
  93}
  94#else
  95#define make_le32(val) (val)
  96#endif
  97static inline void make_le32_n(uint32_t *val, unsigned int num)
  98{
  99        while (num--) {
 100                *val = make_le32(*val);
 101                val++;
 102        }
 103}
 104
 105        /******************/
 106        /* Portal access  */
 107        /******************/
 108struct qbman_swp_sys {
 109        /* On GPP, the sys support for qbman_swp is here. The CENA region isi
 110         * not an mmap() of the real portal registers, but an allocated
 111         * place-holder, because the actual writes/reads to/from the portal are
 112         * marshalled from these allocated areas using QBMan's "MC access
 113         * registers". CINH accesses are atomic so there's no need for a
 114         * place-holder. */
 115        void *cena;
 116        void __iomem *addr_cena;
 117        void __iomem *addr_cinh;
 118};
 119
 120/* P_OFFSET is (ACCESS_CMD,0,12) - offset within the portal
 121 * C is (ACCESS_CMD,12,1) - is inhibited? (0==CENA, 1==CINH)
 122 * SWP_IDX is (ACCESS_CMD,16,10) - Software portal index
 123 * P is (ACCESS_CMD,28,1) - (0==special portal, 1==any portal)
 124 * T is (ACCESS_CMD,29,1) - Command type (0==READ, 1==WRITE)
 125 * E is (ACCESS_CMD,31,1) - Command execute (1 to issue, poll for 0==complete)
 126 */
 127
 128static inline void qbman_cinh_write(struct qbman_swp_sys *s, uint32_t offset,
 129                                    uint32_t val)
 130{
 131        __raw_writel(val, s->addr_cinh + offset);
 132#ifdef QBMAN_CINH_TRACE
 133        pr_info("qbman_cinh_write(%p:0x%03x) 0x%08x\n",
 134                s->addr_cinh, offset, val);
 135#endif
 136}
 137
 138static inline uint32_t qbman_cinh_read(struct qbman_swp_sys *s, uint32_t offset)
 139{
 140        uint32_t reg = __raw_readl(s->addr_cinh + offset);
 141
 142#ifdef QBMAN_CINH_TRACE
 143        pr_info("qbman_cinh_read(%p:0x%03x) 0x%08x\n",
 144                s->addr_cinh, offset, reg);
 145#endif
 146        return reg;
 147}
 148
 149static inline void *qbman_cena_write_start(struct qbman_swp_sys *s,
 150                                                uint32_t offset)
 151{
 152        void *shadow = s->cena + offset;
 153
 154#ifdef QBMAN_CENA_TRACE
 155        pr_info("qbman_cena_write_start(%p:0x%03x) %p\n",
 156                s->addr_cena, offset, shadow);
 157#endif
 158        BUG_ON(offset & 63);
 159        dcbz(shadow);
 160        return shadow;
 161}
 162
 163static inline void qbman_cena_write_complete(struct qbman_swp_sys *s,
 164                                                uint32_t offset, void *cmd)
 165{
 166        const uint32_t *shadow = cmd;
 167        int loop;
 168
 169#ifdef QBMAN_CENA_TRACE
 170        pr_info("qbman_cena_write_complete(%p:0x%03x) %p\n",
 171                s->addr_cena, offset, shadow);
 172        hexdump(cmd, 64);
 173#endif
 174        for (loop = 15; loop >= 0; loop--)
 175#ifdef QBMAN_CINH_ONLY
 176                __raw_writel(shadow[loop], s->addr_cinh +
 177                                         offset + loop * 4);
 178#else
 179                __raw_writel(shadow[loop], s->addr_cena +
 180                                         offset + loop * 4);
 181#endif
 182}
 183
 184static inline void *qbman_cena_read(struct qbman_swp_sys *s, uint32_t offset)
 185{
 186        uint32_t *shadow = s->cena + offset;
 187        unsigned int loop;
 188
 189#ifdef QBMAN_CENA_TRACE
 190        pr_info("qbman_cena_read(%p:0x%03x) %p\n",
 191                s->addr_cena, offset, shadow);
 192#endif
 193
 194        for (loop = 0; loop < 16; loop++)
 195#ifdef QBMAN_CINH_ONLY
 196                shadow[loop] = __raw_readl(s->addr_cinh + offset
 197                                        + loop * 4);
 198#else
 199                shadow[loop] = __raw_readl(s->addr_cena + offset
 200                                        + loop * 4);
 201#endif
 202#ifdef QBMAN_CENA_TRACE
 203        hexdump(shadow, 64);
 204#endif
 205        return shadow;
 206}
 207
 208static inline void qbman_cena_invalidate_prefetch(struct qbman_swp_sys *s,
 209                                                  uint32_t offset)
 210{
 211}
 212
 213        /******************/
 214        /* Portal support */
 215        /******************/
 216
 217/* The SWP_CFG portal register is special, in that it is used by the
 218 * platform-specific code rather than the platform-independent code in
 219 * qbman_portal.c. So use of it is declared locally here. */
 220#define QBMAN_CINH_SWP_CFG   0xd00
 221
 222/* For MC portal use, we always configure with
 223 * DQRR_MF is (SWP_CFG,20,3) - DQRR max fill (<- 0x4)
 224 * EST is (SWP_CFG,16,3) - EQCR_CI stashing threshold (<- 0x0)
 225 * RPM is (SWP_CFG,12,2) - RCR production notification mode (<- 0x3)
 226 * DCM is (SWP_CFG,10,2) - DQRR consumption notification mode (<- 0x2)
 227 * EPM is (SWP_CFG,8,2) - EQCR production notification mode (<- 0x3)
 228 * SD is (SWP_CFG,5,1) - memory stashing drop enable (<- FALSE)
 229 * SP is (SWP_CFG,4,1) - memory stashing priority (<- TRUE)
 230 * SE is (SWP_CFG,3,1) - memory stashing enable (<- 0x0)
 231 * DP is (SWP_CFG,2,1) - dequeue stashing priority (<- TRUE)
 232 * DE is (SWP_CFG,1,1) - dequeue stashing enable (<- 0x0)
 233 * EP is (SWP_CFG,0,1) - EQCR_CI stashing priority (<- FALSE)
 234 */
 235static inline uint32_t qbman_set_swp_cfg(uint8_t max_fill, uint8_t wn,
 236                                        uint8_t est, uint8_t rpm, uint8_t dcm,
 237                                        uint8_t epm, int sd, int sp, int se,
 238                                        int dp, int de, int ep)
 239{
 240        uint32_t reg;
 241
 242        reg = e32_uint8_t(20, (uint32_t)(3 + (max_fill >> 3)), max_fill) |
 243                e32_uint8_t(16, 3, est) | e32_uint8_t(12, 2, rpm) |
 244                e32_uint8_t(10, 2, dcm) | e32_uint8_t(8, 2, epm) |
 245                e32_int(5, 1, sd) | e32_int(4, 1, sp) | e32_int(3, 1, se) |
 246                e32_int(2, 1, dp) | e32_int(1, 1, de) | e32_int(0, 1, ep) |
 247                e32_uint8_t(14, 1, wn);
 248        return reg;
 249}
 250
 251static inline int qbman_swp_sys_init(struct qbman_swp_sys *s,
 252                                     const struct qbman_swp_desc *d,
 253                                     uint8_t dqrr_size)
 254{
 255        uint32_t reg;
 256
 257        s->addr_cena = d->cena_bar;
 258        s->addr_cinh = d->cinh_bar;
 259        s->cena = (void *)valloc(CONFIG_SYS_PAGE_SIZE);
 260        if (!s->cena) {
 261                printf("Could not allocate page for cena shadow\n");
 262                return -1;
 263        }
 264        memset((void *)s->cena, 0x00, CONFIG_SYS_PAGE_SIZE);
 265
 266#ifdef QBMAN_CHECKING
 267        /* We should never be asked to initialise for a portal that isn't in
 268         * the power-on state. (Ie. don't forget to reset portals when they are
 269         * decommissioned!)
 270         */
 271        reg = qbman_cinh_read(s, QBMAN_CINH_SWP_CFG);
 272        BUG_ON(reg);
 273#endif
 274#ifdef QBMAN_CINH_ONLY
 275        reg = qbman_set_swp_cfg(dqrr_size, 1, 0, 3, 2, 3, 0, 1, 0, 1, 0, 0);
 276#else
 277        reg = qbman_set_swp_cfg(dqrr_size, 0, 0, 3, 2, 3, 0, 1, 0, 1, 0, 0);
 278#endif
 279        qbman_cinh_write(s, QBMAN_CINH_SWP_CFG, reg);
 280        reg = qbman_cinh_read(s, QBMAN_CINH_SWP_CFG);
 281        if (!reg) {
 282                printf("The portal is not enabled!\n");
 283                free(s->cena);
 284                return -1;
 285        }
 286        return 0;
 287}
 288
 289static inline void qbman_swp_sys_finish(struct qbman_swp_sys *s)
 290{
 291        free((void *)s->cena);
 292}
 293