linux/drivers/bus/mvebu-mbus.c
<<
>>
Prefs
   1/*
   2 * Address map functions for Marvell EBU SoCs (Kirkwood, Armada
   3 * 370/XP, Dove, Orion5x and MV78xx0)
   4 *
   5 * This file is licensed under the terms of the GNU General Public
   6 * License version 2.  This program is licensed "as is" without any
   7 * warranty of any kind, whether express or implied.
   8 *
   9 * The Marvell EBU SoCs have a configurable physical address space:
  10 * the physical address at which certain devices (PCIe, NOR, NAND,
  11 * etc.) sit can be configured. The configuration takes place through
  12 * two sets of registers:
  13 *
  14 * - One to configure the access of the CPU to the devices. Depending
  15 *   on the families, there are between 8 and 20 configurable windows,
  16 *   each can be use to create a physical memory window that maps to a
  17 *   specific device. Devices are identified by a tuple (target,
  18 *   attribute).
  19 *
  20 * - One to configure the access to the CPU to the SDRAM. There are
  21 *   either 2 (for Dove) or 4 (for other families) windows to map the
  22 *   SDRAM into the physical address space.
  23 *
  24 * This driver:
  25 *
  26 * - Reads out the SDRAM address decoding windows at initialization
  27 *   time, and fills the mvebu_mbus_dram_info structure with these
  28 *   informations. The exported function mv_mbus_dram_info() allow
  29 *   device drivers to get those informations related to the SDRAM
  30 *   address decoding windows. This is because devices also have their
  31 *   own windows (configured through registers that are part of each
  32 *   device register space), and therefore the drivers for Marvell
  33 *   devices have to configure those device -> SDRAM windows to ensure
  34 *   that DMA works properly.
  35 *
  36 * - Provides an API for platform code or device drivers to
  37 *   dynamically add or remove address decoding windows for the CPU ->
  38 *   device accesses. This API is mvebu_mbus_add_window(),
  39 *   mvebu_mbus_add_window_remap_flags() and
  40 *   mvebu_mbus_del_window(). Since the (target, attribute) values
  41 *   differ from one SoC family to another, the API uses a 'const char
  42 *   *' string to identify devices, and this driver is responsible for
  43 *   knowing the mapping between the name of a device and its
  44 *   corresponding (target, attribute) in the current SoC family.
  45 *
  46 * - Provides a debugfs interface in /sys/kernel/debug/mvebu-mbus/ to
  47 *   see the list of CPU -> SDRAM windows and their configuration
  48 *   (file 'sdram') and the list of CPU -> devices windows and their
  49 *   configuration (file 'devices').
  50 */
  51
  52#include <linux/kernel.h>
  53#include <linux/module.h>
  54#include <linux/init.h>
  55#include <linux/mbus.h>
  56#include <linux/io.h>
  57#include <linux/ioport.h>
  58#include <linux/of.h>
  59#include <linux/of_address.h>
  60#include <linux/debugfs.h>
  61
  62/*
  63 * DDR target is the same on all platforms.
  64 */
  65#define TARGET_DDR              0
  66
  67/*
  68 * CPU Address Decode Windows registers
  69 */
  70#define WIN_CTRL_OFF            0x0000
  71#define   WIN_CTRL_ENABLE       BIT(0)
  72#define   WIN_CTRL_TGT_MASK     0xf0
  73#define   WIN_CTRL_TGT_SHIFT    4
  74#define   WIN_CTRL_ATTR_MASK    0xff00
  75#define   WIN_CTRL_ATTR_SHIFT   8
  76#define   WIN_CTRL_SIZE_MASK    0xffff0000
  77#define   WIN_CTRL_SIZE_SHIFT   16
  78#define WIN_BASE_OFF            0x0004
  79#define   WIN_BASE_LOW          0xffff0000
  80#define   WIN_BASE_HIGH         0xf
  81#define WIN_REMAP_LO_OFF        0x0008
  82#define   WIN_REMAP_LOW         0xffff0000
  83#define WIN_REMAP_HI_OFF        0x000c
  84
  85#define ATTR_HW_COHERENCY       (0x1 << 4)
  86
  87#define DDR_BASE_CS_OFF(n)      (0x0000 + ((n) << 3))
  88#define  DDR_BASE_CS_HIGH_MASK  0xf
  89#define  DDR_BASE_CS_LOW_MASK   0xff000000
  90#define DDR_SIZE_CS_OFF(n)      (0x0004 + ((n) << 3))
  91#define  DDR_SIZE_ENABLED       BIT(0)
  92#define  DDR_SIZE_CS_MASK       0x1c
  93#define  DDR_SIZE_CS_SHIFT      2
  94#define  DDR_SIZE_MASK          0xff000000
  95
  96#define DOVE_DDR_BASE_CS_OFF(n) ((n) << 4)
  97
  98struct mvebu_mbus_mapping {
  99        const char *name;
 100        u8 target;
 101        u8 attr;
 102        u8 attrmask;
 103};
 104
 105/*
 106 * Masks used for the 'attrmask' field of mvebu_mbus_mapping. They
 107 * allow to get the real attribute value, discarding the special bits
 108 * used to select a PCI MEM region or a PCI WA region. This allows the
 109 * debugfs code to reverse-match the name of a device from its
 110 * target/attr values.
 111 *
 112 * For all devices except PCI, all bits of 'attr' must be
 113 * considered. For most SoCs, only bit 3 should be ignored (it allows
 114 * to select between PCI MEM and PCI I/O). On Orion5x however, there
 115 * is the special bit 5 to select a PCI WA region.
 116 */
 117#define MAPDEF_NOMASK       0xff
 118#define MAPDEF_PCIMASK      0xf7
 119#define MAPDEF_ORIONPCIMASK 0xd7
 120
 121/* Macro used to define one mvebu_mbus_mapping entry */
 122#define MAPDEF(__n, __t, __a, __m) \
 123        { .name = __n, .target = __t, .attr = __a, .attrmask = __m }
 124
 125struct mvebu_mbus_state;
 126
 127struct mvebu_mbus_soc_data {
 128        unsigned int num_wins;
 129        unsigned int num_remappable_wins;
 130        unsigned int (*win_cfg_offset)(const int win);
 131        void (*setup_cpu_target)(struct mvebu_mbus_state *s);
 132        int (*show_cpu_target)(struct mvebu_mbus_state *s,
 133                               struct seq_file *seq, void *v);
 134        const struct mvebu_mbus_mapping *map;
 135};
 136
 137struct mvebu_mbus_state {
 138        void __iomem *mbuswins_base;
 139        void __iomem *sdramwins_base;
 140        struct dentry *debugfs_root;
 141        struct dentry *debugfs_sdram;
 142        struct dentry *debugfs_devs;
 143        const struct mvebu_mbus_soc_data *soc;
 144        int hw_io_coherency;
 145};
 146
 147static struct mvebu_mbus_state mbus_state;
 148
 149static struct mbus_dram_target_info mvebu_mbus_dram_info;
 150const struct mbus_dram_target_info *mv_mbus_dram_info(void)
 151{
 152        return &mvebu_mbus_dram_info;
 153}
 154EXPORT_SYMBOL_GPL(mv_mbus_dram_info);
 155
 156/*
 157 * Functions to manipulate the address decoding windows
 158 */
 159
 160static void mvebu_mbus_read_window(struct mvebu_mbus_state *mbus,
 161                                   int win, int *enabled, u64 *base,
 162                                   u32 *size, u8 *target, u8 *attr,
 163                                   u64 *remap)
 164{
 165        void __iomem *addr = mbus->mbuswins_base +
 166                mbus->soc->win_cfg_offset(win);
 167        u32 basereg = readl(addr + WIN_BASE_OFF);
 168        u32 ctrlreg = readl(addr + WIN_CTRL_OFF);
 169
 170        if (!(ctrlreg & WIN_CTRL_ENABLE)) {
 171                *enabled = 0;
 172                return;
 173        }
 174
 175        *enabled = 1;
 176        *base = ((u64)basereg & WIN_BASE_HIGH) << 32;
 177        *base |= (basereg & WIN_BASE_LOW);
 178        *size = (ctrlreg | ~WIN_CTRL_SIZE_MASK) + 1;
 179
 180        if (target)
 181                *target = (ctrlreg & WIN_CTRL_TGT_MASK) >> WIN_CTRL_TGT_SHIFT;
 182
 183        if (attr)
 184                *attr = (ctrlreg & WIN_CTRL_ATTR_MASK) >> WIN_CTRL_ATTR_SHIFT;
 185
 186        if (remap) {
 187                if (win < mbus->soc->num_remappable_wins) {
 188                        u32 remap_low = readl(addr + WIN_REMAP_LO_OFF);
 189                        u32 remap_hi  = readl(addr + WIN_REMAP_HI_OFF);
 190                        *remap = ((u64)remap_hi << 32) | remap_low;
 191                } else
 192                        *remap = 0;
 193        }
 194}
 195
 196static void mvebu_mbus_disable_window(struct mvebu_mbus_state *mbus,
 197                                      int win)
 198{
 199        void __iomem *addr;
 200
 201        addr = mbus->mbuswins_base + mbus->soc->win_cfg_offset(win);
 202
 203        writel(0, addr + WIN_BASE_OFF);
 204        writel(0, addr + WIN_CTRL_OFF);
 205        if (win < mbus->soc->num_remappable_wins) {
 206                writel(0, addr + WIN_REMAP_LO_OFF);
 207                writel(0, addr + WIN_REMAP_HI_OFF);
 208        }
 209}
 210
 211/* Checks whether the given window number is available */
 212static int mvebu_mbus_window_is_free(struct mvebu_mbus_state *mbus,
 213                                     const int win)
 214{
 215        void __iomem *addr = mbus->mbuswins_base +
 216                mbus->soc->win_cfg_offset(win);
 217        u32 ctrl = readl(addr + WIN_CTRL_OFF);
 218        return !(ctrl & WIN_CTRL_ENABLE);
 219}
 220
 221/*
 222 * Checks whether the given (base, base+size) area doesn't overlap an
 223 * existing region
 224 */
 225static int mvebu_mbus_window_conflicts(struct mvebu_mbus_state *mbus,
 226                                       phys_addr_t base, size_t size,
 227                                       u8 target, u8 attr)
 228{
 229        u64 end = (u64)base + size;
 230        int win;
 231
 232        for (win = 0; win < mbus->soc->num_wins; win++) {
 233                u64 wbase, wend;
 234                u32 wsize;
 235                u8 wtarget, wattr;
 236                int enabled;
 237
 238                mvebu_mbus_read_window(mbus, win,
 239                                       &enabled, &wbase, &wsize,
 240                                       &wtarget, &wattr, NULL);
 241
 242                if (!enabled)
 243                        continue;
 244
 245                wend = wbase + wsize;
 246
 247                /*
 248                 * Check if the current window overlaps with the
 249                 * proposed physical range
 250                 */
 251                if ((u64)base < wend && end > wbase)
 252                        return 0;
 253
 254                /*
 255                 * Check if target/attribute conflicts
 256                 */
 257                if (target == wtarget && attr == wattr)
 258                        return 0;
 259        }
 260
 261        return 1;
 262}
 263
 264static int mvebu_mbus_find_window(struct mvebu_mbus_state *mbus,
 265                                  phys_addr_t base, size_t size)
 266{
 267        int win;
 268
 269        for (win = 0; win < mbus->soc->num_wins; win++) {
 270                u64 wbase;
 271                u32 wsize;
 272                int enabled;
 273
 274                mvebu_mbus_read_window(mbus, win,
 275                                       &enabled, &wbase, &wsize,
 276                                       NULL, NULL, NULL);
 277
 278                if (!enabled)
 279                        continue;
 280
 281                if (base == wbase && size == wsize)
 282                        return win;
 283        }
 284
 285        return -ENODEV;
 286}
 287
 288static int mvebu_mbus_setup_window(struct mvebu_mbus_state *mbus,
 289                                   int win, phys_addr_t base, size_t size,
 290                                   phys_addr_t remap, u8 target,
 291                                   u8 attr)
 292{
 293        void __iomem *addr = mbus->mbuswins_base +
 294                mbus->soc->win_cfg_offset(win);
 295        u32 ctrl, remap_addr;
 296
 297        ctrl = ((size - 1) & WIN_CTRL_SIZE_MASK) |
 298                (attr << WIN_CTRL_ATTR_SHIFT)    |
 299                (target << WIN_CTRL_TGT_SHIFT)   |
 300                WIN_CTRL_ENABLE;
 301
 302        writel(base & WIN_BASE_LOW, addr + WIN_BASE_OFF);
 303        writel(ctrl, addr + WIN_CTRL_OFF);
 304        if (win < mbus->soc->num_remappable_wins) {
 305                if (remap == MVEBU_MBUS_NO_REMAP)
 306                        remap_addr = base;
 307                else
 308                        remap_addr = remap;
 309                writel(remap_addr & WIN_REMAP_LOW, addr + WIN_REMAP_LO_OFF);
 310                writel(0, addr + WIN_REMAP_HI_OFF);
 311        }
 312
 313        return 0;
 314}
 315
 316static int mvebu_mbus_alloc_window(struct mvebu_mbus_state *mbus,
 317                                   phys_addr_t base, size_t size,
 318                                   phys_addr_t remap, u8 target,
 319                                   u8 attr)
 320{
 321        int win;
 322
 323        if (remap == MVEBU_MBUS_NO_REMAP) {
 324                for (win = mbus->soc->num_remappable_wins;
 325                     win < mbus->soc->num_wins; win++)
 326                        if (mvebu_mbus_window_is_free(mbus, win))
 327                                return mvebu_mbus_setup_window(mbus, win, base,
 328                                                               size, remap,
 329                                                               target, attr);
 330        }
 331
 332
 333        for (win = 0; win < mbus->soc->num_wins; win++)
 334                if (mvebu_mbus_window_is_free(mbus, win))
 335                        return mvebu_mbus_setup_window(mbus, win, base, size,
 336                                                       remap, target, attr);
 337
 338        return -ENOMEM;
 339}
 340
 341/*
 342 * Debugfs debugging
 343 */
 344
 345/* Common function used for Dove, Kirkwood, Armada 370/XP and Orion 5x */
 346static int mvebu_sdram_debug_show_orion(struct mvebu_mbus_state *mbus,
 347                                        struct seq_file *seq, void *v)
 348{
 349        int i;
 350
 351        for (i = 0; i < 4; i++) {
 352                u32 basereg = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i));
 353                u32 sizereg = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i));
 354                u64 base;
 355                u32 size;
 356
 357                if (!(sizereg & DDR_SIZE_ENABLED)) {
 358                        seq_printf(seq, "[%d] disabled\n", i);
 359                        continue;
 360                }
 361
 362                base = ((u64)basereg & DDR_BASE_CS_HIGH_MASK) << 32;
 363                base |= basereg & DDR_BASE_CS_LOW_MASK;
 364                size = (sizereg | ~DDR_SIZE_MASK);
 365
 366                seq_printf(seq, "[%d] %016llx - %016llx : cs%d\n",
 367                           i, (unsigned long long)base,
 368                           (unsigned long long)base + size + 1,
 369                           (sizereg & DDR_SIZE_CS_MASK) >> DDR_SIZE_CS_SHIFT);
 370        }
 371
 372        return 0;
 373}
 374
 375/* Special function for Dove */
 376static int mvebu_sdram_debug_show_dove(struct mvebu_mbus_state *mbus,
 377                                       struct seq_file *seq, void *v)
 378{
 379        int i;
 380
 381        for (i = 0; i < 2; i++) {
 382                u32 map = readl(mbus->sdramwins_base + DOVE_DDR_BASE_CS_OFF(i));
 383                u64 base;
 384                u32 size;
 385
 386                if (!(map & 1)) {
 387                        seq_printf(seq, "[%d] disabled\n", i);
 388                        continue;
 389                }
 390
 391                base = map & 0xff800000;
 392                size = 0x100000 << (((map & 0x000f0000) >> 16) - 4);
 393
 394                seq_printf(seq, "[%d] %016llx - %016llx : cs%d\n",
 395                           i, (unsigned long long)base,
 396                           (unsigned long long)base + size, i);
 397        }
 398
 399        return 0;
 400}
 401
 402static int mvebu_sdram_debug_show(struct seq_file *seq, void *v)
 403{
 404        struct mvebu_mbus_state *mbus = &mbus_state;
 405        return mbus->soc->show_cpu_target(mbus, seq, v);
 406}
 407
 408static int mvebu_sdram_debug_open(struct inode *inode, struct file *file)
 409{
 410        return single_open(file, mvebu_sdram_debug_show, inode->i_private);
 411}
 412
 413static const struct file_operations mvebu_sdram_debug_fops = {
 414        .open = mvebu_sdram_debug_open,
 415        .read = seq_read,
 416        .llseek = seq_lseek,
 417        .release = single_release,
 418};
 419
 420static int mvebu_devs_debug_show(struct seq_file *seq, void *v)
 421{
 422        struct mvebu_mbus_state *mbus = &mbus_state;
 423        int win;
 424
 425        for (win = 0; win < mbus->soc->num_wins; win++) {
 426                u64 wbase, wremap;
 427                u32 wsize;
 428                u8 wtarget, wattr;
 429                int enabled, i;
 430                const char *name;
 431
 432                mvebu_mbus_read_window(mbus, win,
 433                                       &enabled, &wbase, &wsize,
 434                                       &wtarget, &wattr, &wremap);
 435
 436                if (!enabled) {
 437                        seq_printf(seq, "[%02d] disabled\n", win);
 438                        continue;
 439                }
 440
 441
 442                for (i = 0; mbus->soc->map[i].name; i++)
 443                        if (mbus->soc->map[i].target == wtarget &&
 444                            mbus->soc->map[i].attr ==
 445                            (wattr & mbus->soc->map[i].attrmask))
 446                                break;
 447
 448                name = mbus->soc->map[i].name ?: "unknown";
 449
 450                seq_printf(seq, "[%02d] %016llx - %016llx : %s",
 451                           win, (unsigned long long)wbase,
 452                           (unsigned long long)(wbase + wsize), name);
 453
 454                if (win < mbus->soc->num_remappable_wins) {
 455                        seq_printf(seq, " (remap %016llx)\n",
 456                                   (unsigned long long)wremap);
 457                } else
 458                        seq_printf(seq, "\n");
 459        }
 460
 461        return 0;
 462}
 463
 464static int mvebu_devs_debug_open(struct inode *inode, struct file *file)
 465{
 466        return single_open(file, mvebu_devs_debug_show, inode->i_private);
 467}
 468
 469static const struct file_operations mvebu_devs_debug_fops = {
 470        .open = mvebu_devs_debug_open,
 471        .read = seq_read,
 472        .llseek = seq_lseek,
 473        .release = single_release,
 474};
 475
 476/*
 477 * SoC-specific functions and definitions
 478 */
 479
 480static unsigned int orion_mbus_win_offset(int win)
 481{
 482        return win << 4;
 483}
 484
 485static unsigned int armada_370_xp_mbus_win_offset(int win)
 486{
 487        /* The register layout is a bit annoying and the below code
 488         * tries to cope with it.
 489         * - At offset 0x0, there are the registers for the first 8
 490         *   windows, with 4 registers of 32 bits per window (ctrl,
 491         *   base, remap low, remap high)
 492         * - Then at offset 0x80, there is a hole of 0x10 bytes for
 493         *   the internal registers base address and internal units
 494         *   sync barrier register.
 495         * - Then at offset 0x90, there the registers for 12
 496         *   windows, with only 2 registers of 32 bits per window
 497         *   (ctrl, base).
 498         */
 499        if (win < 8)
 500                return win << 4;
 501        else
 502                return 0x90 + ((win - 8) << 3);
 503}
 504
 505static unsigned int mv78xx0_mbus_win_offset(int win)
 506{
 507        if (win < 8)
 508                return win << 4;
 509        else
 510                return 0x900 + ((win - 8) << 4);
 511}
 512
 513static void __init
 514mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus)
 515{
 516        int i;
 517        int cs;
 518
 519        mvebu_mbus_dram_info.mbus_dram_target_id = TARGET_DDR;
 520
 521        for (i = 0, cs = 0; i < 4; i++) {
 522                u32 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i));
 523                u32 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i));
 524
 525                /*
 526                 * We only take care of entries for which the chip
 527                 * select is enabled, and that don't have high base
 528                 * address bits set (devices can only access the first
 529                 * 32 bits of the memory).
 530                 */
 531                if ((size & DDR_SIZE_ENABLED) &&
 532                    !(base & DDR_BASE_CS_HIGH_MASK)) {
 533                        struct mbus_dram_window *w;
 534
 535                        w = &mvebu_mbus_dram_info.cs[cs++];
 536                        w->cs_index = i;
 537                        w->mbus_attr = 0xf & ~(1 << i);
 538                        if (mbus->hw_io_coherency)
 539                                w->mbus_attr |= ATTR_HW_COHERENCY;
 540                        w->base = base & DDR_BASE_CS_LOW_MASK;
 541                        w->size = (size | ~DDR_SIZE_MASK) + 1;
 542                }
 543        }
 544        mvebu_mbus_dram_info.num_cs = cs;
 545}
 546
 547static void __init
 548mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus)
 549{
 550        int i;
 551        int cs;
 552
 553        mvebu_mbus_dram_info.mbus_dram_target_id = TARGET_DDR;
 554
 555        for (i = 0, cs = 0; i < 2; i++) {
 556                u32 map = readl(mbus->sdramwins_base + DOVE_DDR_BASE_CS_OFF(i));
 557
 558                /*
 559                 * Chip select enabled?
 560                 */
 561                if (map & 1) {
 562                        struct mbus_dram_window *w;
 563
 564                        w = &mvebu_mbus_dram_info.cs[cs++];
 565                        w->cs_index = i;
 566                        w->mbus_attr = 0; /* CS address decoding done inside */
 567                                          /* the DDR controller, no need to  */
 568                                          /* provide attributes */
 569                        w->base = map & 0xff800000;
 570                        w->size = 0x100000 << (((map & 0x000f0000) >> 16) - 4);
 571                }
 572        }
 573
 574        mvebu_mbus_dram_info.num_cs = cs;
 575}
 576
 577static const struct mvebu_mbus_mapping armada_370_map[] = {
 578        MAPDEF("bootrom",     1, 0xe0, MAPDEF_NOMASK),
 579        MAPDEF("devbus-boot", 1, 0x2f, MAPDEF_NOMASK),
 580        MAPDEF("devbus-cs0",  1, 0x3e, MAPDEF_NOMASK),
 581        MAPDEF("devbus-cs1",  1, 0x3d, MAPDEF_NOMASK),
 582        MAPDEF("devbus-cs2",  1, 0x3b, MAPDEF_NOMASK),
 583        MAPDEF("devbus-cs3",  1, 0x37, MAPDEF_NOMASK),
 584        MAPDEF("pcie0.0",     4, 0xe0, MAPDEF_PCIMASK),
 585        MAPDEF("pcie1.0",     8, 0xe0, MAPDEF_PCIMASK),
 586        {},
 587};
 588
 589static const struct mvebu_mbus_soc_data armada_370_mbus_data = {
 590        .num_wins            = 20,
 591        .num_remappable_wins = 8,
 592        .win_cfg_offset      = armada_370_xp_mbus_win_offset,
 593        .setup_cpu_target    = mvebu_mbus_default_setup_cpu_target,
 594        .show_cpu_target     = mvebu_sdram_debug_show_orion,
 595        .map                 = armada_370_map,
 596};
 597
 598static const struct mvebu_mbus_mapping armada_xp_map[] = {
 599        MAPDEF("bootrom",     1, 0x1d, MAPDEF_NOMASK),
 600        MAPDEF("devbus-boot", 1, 0x2f, MAPDEF_NOMASK),
 601        MAPDEF("devbus-cs0",  1, 0x3e, MAPDEF_NOMASK),
 602        MAPDEF("devbus-cs1",  1, 0x3d, MAPDEF_NOMASK),
 603        MAPDEF("devbus-cs2",  1, 0x3b, MAPDEF_NOMASK),
 604        MAPDEF("devbus-cs3",  1, 0x37, MAPDEF_NOMASK),
 605        MAPDEF("pcie0.0",     4, 0xe0, MAPDEF_PCIMASK),
 606        MAPDEF("pcie0.1",     4, 0xd0, MAPDEF_PCIMASK),
 607        MAPDEF("pcie0.2",     4, 0xb0, MAPDEF_PCIMASK),
 608        MAPDEF("pcie0.3",     4, 0x70, MAPDEF_PCIMASK),
 609        MAPDEF("pcie1.0",     8, 0xe0, MAPDEF_PCIMASK),
 610        MAPDEF("pcie1.1",     8, 0xd0, MAPDEF_PCIMASK),
 611        MAPDEF("pcie1.2",     8, 0xb0, MAPDEF_PCIMASK),
 612        MAPDEF("pcie1.3",     8, 0x70, MAPDEF_PCIMASK),
 613        MAPDEF("pcie2.0",     4, 0xf0, MAPDEF_PCIMASK),
 614        MAPDEF("pcie3.0",     8, 0xf0, MAPDEF_PCIMASK),
 615        {},
 616};
 617
 618static const struct mvebu_mbus_soc_data armada_xp_mbus_data = {
 619        .num_wins            = 20,
 620        .num_remappable_wins = 8,
 621        .win_cfg_offset      = armada_370_xp_mbus_win_offset,
 622        .setup_cpu_target    = mvebu_mbus_default_setup_cpu_target,
 623        .show_cpu_target     = mvebu_sdram_debug_show_orion,
 624        .map                 = armada_xp_map,
 625};
 626
 627static const struct mvebu_mbus_mapping kirkwood_map[] = {
 628        MAPDEF("pcie0.0", 4, 0xe0, MAPDEF_PCIMASK),
 629        MAPDEF("pcie1.0", 4, 0xd0, MAPDEF_PCIMASK),
 630        MAPDEF("sram",    3, 0x01, MAPDEF_NOMASK),
 631        MAPDEF("nand",    1, 0x2f, MAPDEF_NOMASK),
 632        {},
 633};
 634
 635static const struct mvebu_mbus_soc_data kirkwood_mbus_data = {
 636        .num_wins            = 8,
 637        .num_remappable_wins = 4,
 638        .win_cfg_offset      = orion_mbus_win_offset,
 639        .setup_cpu_target    = mvebu_mbus_default_setup_cpu_target,
 640        .show_cpu_target     = mvebu_sdram_debug_show_orion,
 641        .map                 = kirkwood_map,
 642};
 643
 644static const struct mvebu_mbus_mapping dove_map[] = {
 645        MAPDEF("pcie0.0",    0x4, 0xe0, MAPDEF_PCIMASK),
 646        MAPDEF("pcie1.0",    0x8, 0xe0, MAPDEF_PCIMASK),
 647        MAPDEF("cesa",       0x3, 0x01, MAPDEF_NOMASK),
 648        MAPDEF("bootrom",    0x1, 0xfd, MAPDEF_NOMASK),
 649        MAPDEF("scratchpad", 0xd, 0x0, MAPDEF_NOMASK),
 650        {},
 651};
 652
 653static const struct mvebu_mbus_soc_data dove_mbus_data = {
 654        .num_wins            = 8,
 655        .num_remappable_wins = 4,
 656        .win_cfg_offset      = orion_mbus_win_offset,
 657        .setup_cpu_target    = mvebu_mbus_dove_setup_cpu_target,
 658        .show_cpu_target     = mvebu_sdram_debug_show_dove,
 659        .map                 = dove_map,
 660};
 661
 662static const struct mvebu_mbus_mapping orion5x_map[] = {
 663        MAPDEF("pcie0.0",     4, 0x51, MAPDEF_ORIONPCIMASK),
 664        MAPDEF("pci0.0",      3, 0x51, MAPDEF_ORIONPCIMASK),
 665        MAPDEF("devbus-boot", 1, 0x0f, MAPDEF_NOMASK),
 666        MAPDEF("devbus-cs0",  1, 0x1e, MAPDEF_NOMASK),
 667        MAPDEF("devbus-cs1",  1, 0x1d, MAPDEF_NOMASK),
 668        MAPDEF("devbus-cs2",  1, 0x1b, MAPDEF_NOMASK),
 669        MAPDEF("sram",        0, 0x00, MAPDEF_NOMASK),
 670        {},
 671};
 672
 673/*
 674 * Some variants of Orion5x have 4 remappable windows, some other have
 675 * only two of them.
 676 */
 677static const struct mvebu_mbus_soc_data orion5x_4win_mbus_data = {
 678        .num_wins            = 8,
 679        .num_remappable_wins = 4,
 680        .win_cfg_offset      = orion_mbus_win_offset,
 681        .setup_cpu_target    = mvebu_mbus_default_setup_cpu_target,
 682        .show_cpu_target     = mvebu_sdram_debug_show_orion,
 683        .map                 = orion5x_map,
 684};
 685
 686static const struct mvebu_mbus_soc_data orion5x_2win_mbus_data = {
 687        .num_wins            = 8,
 688        .num_remappable_wins = 2,
 689        .win_cfg_offset      = orion_mbus_win_offset,
 690        .setup_cpu_target    = mvebu_mbus_default_setup_cpu_target,
 691        .show_cpu_target     = mvebu_sdram_debug_show_orion,
 692        .map                 = orion5x_map,
 693};
 694
 695static const struct mvebu_mbus_mapping mv78xx0_map[] = {
 696        MAPDEF("pcie0.0", 4, 0xe0, MAPDEF_PCIMASK),
 697        MAPDEF("pcie0.1", 4, 0xd0, MAPDEF_PCIMASK),
 698        MAPDEF("pcie0.2", 4, 0xb0, MAPDEF_PCIMASK),
 699        MAPDEF("pcie0.3", 4, 0x70, MAPDEF_PCIMASK),
 700        MAPDEF("pcie1.0", 8, 0xe0, MAPDEF_PCIMASK),
 701        MAPDEF("pcie1.1", 8, 0xd0, MAPDEF_PCIMASK),
 702        MAPDEF("pcie1.2", 8, 0xb0, MAPDEF_PCIMASK),
 703        MAPDEF("pcie1.3", 8, 0x70, MAPDEF_PCIMASK),
 704        MAPDEF("pcie2.0", 4, 0xf0, MAPDEF_PCIMASK),
 705        MAPDEF("pcie3.0", 8, 0xf0, MAPDEF_PCIMASK),
 706        {},
 707};
 708
 709static const struct mvebu_mbus_soc_data mv78xx0_mbus_data = {
 710        .num_wins            = 14,
 711        .num_remappable_wins = 8,
 712        .win_cfg_offset      = mv78xx0_mbus_win_offset,
 713        .setup_cpu_target    = mvebu_mbus_default_setup_cpu_target,
 714        .show_cpu_target     = mvebu_sdram_debug_show_orion,
 715        .map                 = mv78xx0_map,
 716};
 717
 718/*
 719 * The driver doesn't yet have a DT binding because the details of
 720 * this DT binding still need to be sorted out. However, as a
 721 * preparation, we already use of_device_id to match a SoC description
 722 * string against the SoC specific details of this driver.
 723 */
 724static const struct of_device_id of_mvebu_mbus_ids[] = {
 725        { .compatible = "marvell,armada370-mbus",
 726          .data = &armada_370_mbus_data, },
 727        { .compatible = "marvell,armadaxp-mbus",
 728          .data = &armada_xp_mbus_data, },
 729        { .compatible = "marvell,kirkwood-mbus",
 730          .data = &kirkwood_mbus_data, },
 731        { .compatible = "marvell,dove-mbus",
 732          .data = &dove_mbus_data, },
 733        { .compatible = "marvell,orion5x-88f5281-mbus",
 734          .data = &orion5x_4win_mbus_data, },
 735        { .compatible = "marvell,orion5x-88f5182-mbus",
 736          .data = &orion5x_2win_mbus_data, },
 737        { .compatible = "marvell,orion5x-88f5181-mbus",
 738          .data = &orion5x_2win_mbus_data, },
 739        { .compatible = "marvell,orion5x-88f6183-mbus",
 740          .data = &orion5x_4win_mbus_data, },
 741        { .compatible = "marvell,mv78xx0-mbus",
 742          .data = &mv78xx0_mbus_data, },
 743        { },
 744};
 745
 746/*
 747 * Public API of the driver
 748 */
 749int mvebu_mbus_add_window_remap_flags(const char *devname, phys_addr_t base,
 750                                      size_t size, phys_addr_t remap,
 751                                      unsigned int flags)
 752{
 753        struct mvebu_mbus_state *s = &mbus_state;
 754        u8 target, attr;
 755        int i;
 756
 757        if (!s->soc->map)
 758                return -ENODEV;
 759
 760        for (i = 0; s->soc->map[i].name; i++)
 761                if (!strcmp(s->soc->map[i].name, devname))
 762                        break;
 763
 764        if (!s->soc->map[i].name) {
 765                pr_err("mvebu-mbus: unknown device '%s'\n", devname);
 766                return -ENODEV;
 767        }
 768
 769        target = s->soc->map[i].target;
 770        attr   = s->soc->map[i].attr;
 771
 772        if (flags == MVEBU_MBUS_PCI_MEM)
 773                attr |= 0x8;
 774        else if (flags == MVEBU_MBUS_PCI_WA)
 775                attr |= 0x28;
 776
 777        if (!mvebu_mbus_window_conflicts(s, base, size, target, attr)) {
 778                pr_err("mvebu-mbus: cannot add window '%s', conflicts with another window\n",
 779                       devname);
 780                return -EINVAL;
 781        }
 782
 783        return mvebu_mbus_alloc_window(s, base, size, remap, target, attr);
 784
 785}
 786
 787int mvebu_mbus_add_window(const char *devname, phys_addr_t base, size_t size)
 788{
 789        return mvebu_mbus_add_window_remap_flags(devname, base, size,
 790                                                 MVEBU_MBUS_NO_REMAP, 0);
 791}
 792
 793int mvebu_mbus_del_window(phys_addr_t base, size_t size)
 794{
 795        int win;
 796
 797        win = mvebu_mbus_find_window(&mbus_state, base, size);
 798        if (win < 0)
 799                return win;
 800
 801        mvebu_mbus_disable_window(&mbus_state, win);
 802        return 0;
 803}
 804
 805static __init int mvebu_mbus_debugfs_init(void)
 806{
 807        struct mvebu_mbus_state *s = &mbus_state;
 808
 809        /*
 810         * If no base has been initialized, doesn't make sense to
 811         * register the debugfs entries. We may be on a multiplatform
 812         * kernel that isn't running a Marvell EBU SoC.
 813         */
 814        if (!s->mbuswins_base)
 815                return 0;
 816
 817        s->debugfs_root = debugfs_create_dir("mvebu-mbus", NULL);
 818        if (s->debugfs_root) {
 819                s->debugfs_sdram = debugfs_create_file("sdram", S_IRUGO,
 820                                                       s->debugfs_root, NULL,
 821                                                       &mvebu_sdram_debug_fops);
 822                s->debugfs_devs = debugfs_create_file("devices", S_IRUGO,
 823                                                      s->debugfs_root, NULL,
 824                                                      &mvebu_devs_debug_fops);
 825        }
 826
 827        return 0;
 828}
 829fs_initcall(mvebu_mbus_debugfs_init);
 830
 831int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base,
 832                           size_t mbuswins_size,
 833                           phys_addr_t sdramwins_phys_base,
 834                           size_t sdramwins_size)
 835{
 836        struct mvebu_mbus_state *mbus = &mbus_state;
 837        const struct of_device_id *of_id;
 838        int win;
 839
 840        for (of_id = of_mvebu_mbus_ids; of_id->compatible; of_id++)
 841                if (!strcmp(of_id->compatible, soc))
 842                        break;
 843
 844        if (!of_id->compatible) {
 845                pr_err("mvebu-mbus: could not find a matching SoC family\n");
 846                return -ENODEV;
 847        }
 848
 849        mbus->soc = of_id->data;
 850
 851        mbus->mbuswins_base = ioremap(mbuswins_phys_base, mbuswins_size);
 852        if (!mbus->mbuswins_base)
 853                return -ENOMEM;
 854
 855        mbus->sdramwins_base = ioremap(sdramwins_phys_base, sdramwins_size);
 856        if (!mbus->sdramwins_base) {
 857                iounmap(mbus_state.mbuswins_base);
 858                return -ENOMEM;
 859        }
 860
 861        if (of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric"))
 862                mbus->hw_io_coherency = 1;
 863
 864        for (win = 0; win < mbus->soc->num_wins; win++)
 865                mvebu_mbus_disable_window(mbus, win);
 866
 867        mbus->soc->setup_cpu_target(mbus);
 868
 869        return 0;
 870}
 871
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.