linux/drivers/memory/mvebu-devbus.c
<<
>>
Prefs
   1/*
   2 * Marvell EBU SoC Device Bus Controller
   3 * (memory controller for NOR/NAND/SRAM/FPGA devices)
   4 *
   5 * Copyright (C) 2013 Marvell
   6 *
   7 * This program is free software: you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation version 2 of the License.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18 *
  19 */
  20
  21#include <linux/kernel.h>
  22#include <linux/module.h>
  23#include <linux/slab.h>
  24#include <linux/err.h>
  25#include <linux/io.h>
  26#include <linux/clk.h>
  27#include <linux/mbus.h>
  28#include <linux/of_platform.h>
  29#include <linux/of_address.h>
  30#include <linux/platform_device.h>
  31
  32/* Register definitions */
  33#define DEV_WIDTH_BIT           30
  34#define BADR_SKEW_BIT           28
  35#define RD_HOLD_BIT             23
  36#define ACC_NEXT_BIT            17
  37#define RD_SETUP_BIT            12
  38#define ACC_FIRST_BIT           6
  39
  40#define SYNC_ENABLE_BIT         24
  41#define WR_HIGH_BIT             16
  42#define WR_LOW_BIT              8
  43
  44#define READ_PARAM_OFFSET       0x0
  45#define WRITE_PARAM_OFFSET      0x4
  46
  47static const char * const devbus_wins[] = {
  48        "devbus-boot",
  49        "devbus-cs0",
  50        "devbus-cs1",
  51        "devbus-cs2",
  52        "devbus-cs3",
  53};
  54
  55struct devbus_read_params {
  56        u32 bus_width;
  57        u32 badr_skew;
  58        u32 turn_off;
  59        u32 acc_first;
  60        u32 acc_next;
  61        u32 rd_setup;
  62        u32 rd_hold;
  63};
  64
  65struct devbus_write_params {
  66        u32 sync_enable;
  67        u32 wr_high;
  68        u32 wr_low;
  69        u32 ale_wr;
  70};
  71
  72struct devbus {
  73        struct device *dev;
  74        void __iomem *base;
  75        unsigned long tick_ps;
  76};
  77
  78static int get_timing_param_ps(struct devbus *devbus,
  79                               struct device_node *node,
  80                               const char *name,
  81                               u32 *ticks)
  82{
  83        u32 time_ps;
  84        int err;
  85
  86        err = of_property_read_u32(node, name, &time_ps);
  87        if (err < 0) {
  88                dev_err(devbus->dev, "%s has no '%s' property\n",
  89                        name, node->full_name);
  90                return err;
  91        }
  92
  93        *ticks = (time_ps + devbus->tick_ps - 1) / devbus->tick_ps;
  94
  95        dev_dbg(devbus->dev, "%s: %u ps -> 0x%x\n",
  96                name, time_ps, *ticks);
  97        return 0;
  98}
  99
 100static int devbus_set_timing_params(struct devbus *devbus,
 101                                    struct device_node *node)
 102{
 103        struct devbus_read_params r;
 104        struct devbus_write_params w;
 105        u32 value;
 106        int err;
 107
 108        dev_dbg(devbus->dev, "Setting timing parameter, tick is %lu ps\n",
 109                devbus->tick_ps);
 110
 111        /* Get read timings */
 112        err = of_property_read_u32(node, "devbus,bus-width", &r.bus_width);
 113        if (err < 0) {
 114                dev_err(devbus->dev,
 115                        "%s has no 'devbus,bus-width' property\n",
 116                        node->full_name);
 117                return err;
 118        }
 119        /* Convert bit width to byte width */
 120        r.bus_width /= 8;
 121
 122        err = get_timing_param_ps(devbus, node, "devbus,badr-skew-ps",
 123                                 &r.badr_skew);
 124        if (err < 0)
 125                return err;
 126
 127        err = get_timing_param_ps(devbus, node, "devbus,turn-off-ps",
 128                                 &r.turn_off);
 129        if (err < 0)
 130                return err;
 131
 132        err = get_timing_param_ps(devbus, node, "devbus,acc-first-ps",
 133                                 &r.acc_first);
 134        if (err < 0)
 135                return err;
 136
 137        err = get_timing_param_ps(devbus, node, "devbus,acc-next-ps",
 138                                 &r.acc_next);
 139        if (err < 0)
 140                return err;
 141
 142        err = get_timing_param_ps(devbus, node, "devbus,rd-setup-ps",
 143                                 &r.rd_setup);
 144        if (err < 0)
 145                return err;
 146
 147        err = get_timing_param_ps(devbus, node, "devbus,rd-hold-ps",
 148                                 &r.rd_hold);
 149        if (err < 0)
 150                return err;
 151
 152        /* Get write timings */
 153        err = of_property_read_u32(node, "devbus,sync-enable",
 154                                  &w.sync_enable);
 155        if (err < 0) {
 156                dev_err(devbus->dev,
 157                        "%s has no 'devbus,sync-enable' property\n",
 158                        node->full_name);
 159                return err;
 160        }
 161
 162        err = get_timing_param_ps(devbus, node, "devbus,ale-wr-ps",
 163                                 &w.ale_wr);
 164        if (err < 0)
 165                return err;
 166
 167        err = get_timing_param_ps(devbus, node, "devbus,wr-low-ps",
 168                                 &w.wr_low);
 169        if (err < 0)
 170                return err;
 171
 172        err = get_timing_param_ps(devbus, node, "devbus,wr-high-ps",
 173                                 &w.wr_high);
 174        if (err < 0)
 175                return err;
 176
 177        /* Set read timings */
 178        value = r.bus_width << DEV_WIDTH_BIT |
 179                r.badr_skew << BADR_SKEW_BIT |
 180                r.rd_hold   << RD_HOLD_BIT   |
 181                r.acc_next  << ACC_NEXT_BIT  |
 182                r.rd_setup  << RD_SETUP_BIT  |
 183                r.acc_first << ACC_FIRST_BIT |
 184                r.turn_off;
 185
 186        dev_dbg(devbus->dev, "read parameters register 0x%p = 0x%x\n",
 187                devbus->base + READ_PARAM_OFFSET,
 188                value);
 189
 190        writel(value, devbus->base + READ_PARAM_OFFSET);
 191
 192        /* Set write timings */
 193        value = w.sync_enable  << SYNC_ENABLE_BIT |
 194                w.wr_low       << WR_LOW_BIT      |
 195                w.wr_high      << WR_HIGH_BIT     |
 196                w.ale_wr;
 197
 198        dev_dbg(devbus->dev, "write parameters register: 0x%p = 0x%x\n",
 199                devbus->base + WRITE_PARAM_OFFSET,
 200                value);
 201
 202        writel(value, devbus->base + WRITE_PARAM_OFFSET);
 203
 204        return 0;
 205}
 206
 207static int mvebu_devbus_probe(struct platform_device *pdev)
 208{
 209        struct device *dev = &pdev->dev;
 210        struct device_node *node = pdev->dev.of_node;
 211        struct device_node *parent;
 212        struct devbus *devbus;
 213        struct resource *res;
 214        struct clk *clk;
 215        unsigned long rate;
 216        const __be32 *ranges;
 217        int err, cs;
 218        int addr_cells, p_addr_cells, size_cells;
 219        int ranges_len, tuple_len;
 220        u32 base, size;
 221
 222        devbus = devm_kzalloc(&pdev->dev, sizeof(struct devbus), GFP_KERNEL);
 223        if (!devbus)
 224                return -ENOMEM;
 225
 226        devbus->dev = dev;
 227        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 228        devbus->base = devm_ioremap_resource(&pdev->dev, res);
 229        if (IS_ERR(devbus->base))
 230                return PTR_ERR(devbus->base);
 231
 232        clk = devm_clk_get(&pdev->dev, NULL);
 233        if (IS_ERR(clk))
 234                return PTR_ERR(clk);
 235        clk_prepare_enable(clk);
 236
 237        /*
 238         * Obtain clock period in picoseconds,
 239         * we need this in order to convert timing
 240         * parameters from cycles to picoseconds.
 241         */
 242        rate = clk_get_rate(clk) / 1000;
 243        devbus->tick_ps = 1000000000 / rate;
 244
 245        /* Read the device tree node and set the new timing parameters */
 246        err = devbus_set_timing_params(devbus, node);
 247        if (err < 0)
 248                return err;
 249
 250        /*
 251         * Allocate an address window for this device.
 252         * If the device probing fails, then we won't be able to
 253         * remove the allocated address decoding window.
 254         *
 255         * FIXME: This is only a temporary hack! We need to do this here
 256         * because we still don't have device tree bindings for mbus.
 257         * Once that support is added, we will declare these address windows
 258         * statically in the device tree, and remove the window configuration
 259         * from here.
 260         */
 261
 262        /*
 263         * Get the CS to choose the window string.
 264         * This is a bit hacky, but it will be removed once the
 265         * address windows are declared in the device tree.
 266         */
 267        cs = (((unsigned long)devbus->base) % 0x400) / 8;
 268
 269        /*
 270         * Parse 'ranges' property to obtain a (base,size) window tuple.
 271         * This will be removed once the address windows
 272         * are declared in the device tree.
 273         */
 274        parent = of_get_parent(node);
 275        if (!parent)
 276                return -EINVAL;
 277
 278        p_addr_cells = of_n_addr_cells(parent);
 279        of_node_put(parent);
 280
 281        addr_cells = of_n_addr_cells(node);
 282        size_cells = of_n_size_cells(node);
 283        tuple_len = (p_addr_cells + addr_cells + size_cells) * sizeof(__be32);
 284
 285        ranges = of_get_property(node, "ranges", &ranges_len);
 286        if (ranges == NULL || ranges_len != tuple_len)
 287                return -EINVAL;
 288
 289        base = of_translate_address(node, ranges + addr_cells);
 290        if (base == OF_BAD_ADDR)
 291                return -EINVAL;
 292        size = of_read_number(ranges + addr_cells + p_addr_cells, size_cells);
 293
 294        /*
 295         * Create an mbus address windows.
 296         * FIXME: Remove this, together with the above code, once the
 297         * address windows are declared in the device tree.
 298         */
 299        err = mvebu_mbus_add_window(devbus_wins[cs], base, size);
 300        if (err < 0)
 301                return err;
 302
 303        /*
 304         * We need to create a child device explicitly from here to
 305         * guarantee that the child will be probed after the timing
 306         * parameters for the bus are written.
 307         */
 308        err = of_platform_populate(node, NULL, NULL, dev);
 309        if (err < 0) {
 310                mvebu_mbus_del_window(base, size);
 311                return err;
 312        }
 313
 314        return 0;
 315}
 316
 317static const struct of_device_id mvebu_devbus_of_match[] = {
 318        { .compatible = "marvell,mvebu-devbus" },
 319        {},
 320};
 321MODULE_DEVICE_TABLE(of, mvebu_devbus_of_match);
 322
 323static struct platform_driver mvebu_devbus_driver = {
 324        .probe          = mvebu_devbus_probe,
 325        .driver         = {
 326                .name   = "mvebu-devbus",
 327                .owner  = THIS_MODULE,
 328                .of_match_table = mvebu_devbus_of_match,
 329        },
 330};
 331
 332static int __init mvebu_devbus_init(void)
 333{
 334        return platform_driver_register(&mvebu_devbus_driver);
 335}
 336module_init(mvebu_devbus_init);
 337
 338MODULE_LICENSE("GPL v2");
 339MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@free-electrons.com>");
 340MODULE_DESCRIPTION("Marvell EBU SoC Device Bus controller");
 341
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.