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