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
  47struct devbus_read_params {
  48        u32 bus_width;
  49        u32 badr_skew;
  50        u32 turn_off;
  51        u32 acc_first;
  52        u32 acc_next;
  53        u32 rd_setup;
  54        u32 rd_hold;
  55};
  56
  57struct devbus_write_params {
  58        u32 sync_enable;
  59        u32 wr_high;
  60        u32 wr_low;
  61        u32 ale_wr;
  62};
  63
  64struct devbus {
  65        struct device *dev;
  66        void __iomem *base;
  67        unsigned long tick_ps;
  68};
  69
  70static int get_timing_param_ps(struct devbus *devbus,
  71                               struct device_node *node,
  72                               const char *name,
  73                               u32 *ticks)
  74{
  75        u32 time_ps;
  76        int err;
  77
  78        err = of_property_read_u32(node, name, &time_ps);
  79        if (err < 0) {
  80                dev_err(devbus->dev, "%s has no '%s' property\n",
  81                        name, node->full_name);
  82                return err;
  83        }
  84
  85        *ticks = (time_ps + devbus->tick_ps - 1) / devbus->tick_ps;
  86
  87        dev_dbg(devbus->dev, "%s: %u ps -> 0x%x\n",
  88                name, time_ps, *ticks);
  89        return 0;
  90}
  91
  92static int devbus_set_timing_params(struct devbus *devbus,
  93                                    struct device_node *node)
  94{
  95        struct devbus_read_params r;
  96        struct devbus_write_params w;
  97        u32 value;
  98        int err;
  99
 100        dev_dbg(devbus->dev, "Setting timing parameter, tick is %lu ps\n",
 101                devbus->tick_ps);
 102
 103        /* Get read timings */
 104        err = of_property_read_u32(node, "devbus,bus-width", &r.bus_width);
 105        if (err < 0) {
 106                dev_err(devbus->dev,
 107                        "%s has no 'devbus,bus-width' property\n",
 108                        node->full_name);
 109                return err;
 110        }
 111        /* Convert bit width to byte width */
 112        r.bus_width /= 8;
 113
 114        err = get_timing_param_ps(devbus, node, "devbus,badr-skew-ps",
 115                                 &r.badr_skew);
 116        if (err < 0)
 117                return err;
 118
 119        err = get_timing_param_ps(devbus, node, "devbus,turn-off-ps",
 120                                 &r.turn_off);
 121        if (err < 0)
 122                return err;
 123
 124        err = get_timing_param_ps(devbus, node, "devbus,acc-first-ps",
 125                                 &r.acc_first);
 126        if (err < 0)
 127                return err;
 128
 129        err = get_timing_param_ps(devbus, node, "devbus,acc-next-ps",
 130                                 &r.acc_next);
 131        if (err < 0)
 132                return err;
 133
 134        err = get_timing_param_ps(devbus, node, "devbus,rd-setup-ps",
 135                                 &r.rd_setup);
 136        if (err < 0)
 137                return err;
 138
 139        err = get_timing_param_ps(devbus, node, "devbus,rd-hold-ps",
 140                                 &r.rd_hold);
 141        if (err < 0)
 142                return err;
 143
 144        /* Get write timings */
 145        err = of_property_read_u32(node, "devbus,sync-enable",
 146                                  &w.sync_enable);
 147        if (err < 0) {
 148                dev_err(devbus->dev,
 149                        "%s has no 'devbus,sync-enable' property\n",
 150                        node->full_name);
 151                return err;
 152        }
 153
 154        err = get_timing_param_ps(devbus, node, "devbus,ale-wr-ps",
 155                                 &w.ale_wr);
 156        if (err < 0)
 157                return err;
 158
 159        err = get_timing_param_ps(devbus, node, "devbus,wr-low-ps",
 160                                 &w.wr_low);
 161        if (err < 0)
 162                return err;
 163
 164        err = get_timing_param_ps(devbus, node, "devbus,wr-high-ps",
 165                                 &w.wr_high);
 166        if (err < 0)
 167                return err;
 168
 169        /* Set read timings */
 170        value = r.bus_width << DEV_WIDTH_BIT |
 171                r.badr_skew << BADR_SKEW_BIT |
 172                r.rd_hold   << RD_HOLD_BIT   |
 173                r.acc_next  << ACC_NEXT_BIT  |
 174                r.rd_setup  << RD_SETUP_BIT  |
 175                r.acc_first << ACC_FIRST_BIT |
 176                r.turn_off;
 177
 178        dev_dbg(devbus->dev, "read parameters register 0x%p = 0x%x\n",
 179                devbus->base + READ_PARAM_OFFSET,
 180                value);
 181
 182        writel(value, devbus->base + READ_PARAM_OFFSET);
 183
 184        /* Set write timings */
 185        value = w.sync_enable  << SYNC_ENABLE_BIT |
 186                w.wr_low       << WR_LOW_BIT      |
 187                w.wr_high      << WR_HIGH_BIT     |
 188                w.ale_wr;
 189
 190        dev_dbg(devbus->dev, "write parameters register: 0x%p = 0x%x\n",
 191                devbus->base + WRITE_PARAM_OFFSET,
 192                value);
 193
 194        writel(value, devbus->base + WRITE_PARAM_OFFSET);
 195
 196        return 0;
 197}
 198
 199static int mvebu_devbus_probe(struct platform_device *pdev)
 200{
 201        struct device *dev = &pdev->dev;
 202        struct device_node *node = pdev->dev.of_node;
 203        struct devbus *devbus;
 204        struct resource *res;
 205        struct clk *clk;
 206        unsigned long rate;
 207        int err;
 208
 209        devbus = devm_kzalloc(&pdev->dev, sizeof(struct devbus), GFP_KERNEL);
 210        if (!devbus)
 211                return -ENOMEM;
 212
 213        devbus->dev = dev;
 214        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 215        devbus->base = devm_ioremap_resource(&pdev->dev, res);
 216        if (IS_ERR(devbus->base))
 217                return PTR_ERR(devbus->base);
 218
 219        clk = devm_clk_get(&pdev->dev, NULL);
 220        if (IS_ERR(clk))
 221                return PTR_ERR(clk);
 222        clk_prepare_enable(clk);
 223
 224        /*
 225         * Obtain clock period in picoseconds,
 226         * we need this in order to convert timing
 227         * parameters from cycles to picoseconds.
 228         */
 229        rate = clk_get_rate(clk) / 1000;
 230        devbus->tick_ps = 1000000000 / rate;
 231
 232        /* Read the device tree node and set the new timing parameters */
 233        err = devbus_set_timing_params(devbus, node);
 234        if (err < 0)
 235                return err;
 236
 237        /*
 238         * We need to create a child device explicitly from here to
 239         * guarantee that the child will be probed after the timing
 240         * parameters for the bus are written.
 241         */
 242        err = of_platform_populate(node, NULL, NULL, dev);
 243        if (err < 0)
 244                return err;
 245
 246        return 0;
 247}
 248
 249static const struct of_device_id mvebu_devbus_of_match[] = {
 250        { .compatible = "marvell,mvebu-devbus" },
 251        {},
 252};
 253MODULE_DEVICE_TABLE(of, mvebu_devbus_of_match);
 254
 255static struct platform_driver mvebu_devbus_driver = {
 256        .probe          = mvebu_devbus_probe,
 257        .driver         = {
 258                .name   = "mvebu-devbus",
 259                .owner  = THIS_MODULE,
 260                .of_match_table = mvebu_devbus_of_match,
 261        },
 262};
 263
 264static int __init mvebu_devbus_init(void)
 265{
 266        return platform_driver_register(&mvebu_devbus_driver);
 267}
 268module_init(mvebu_devbus_init);
 269
 270MODULE_LICENSE("GPL v2");
 271MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@free-electrons.com>");
 272MODULE_DESCRIPTION("Marvell EBU SoC Device Bus controller");
 273
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.