linux/arch/avr32/mach-at32ap/hsmc.c
<<
>>
Prefs
   1/*
   2 * Static Memory Controller for AT32 chips
   3 *
   4 * Copyright (C) 2006 Atmel Corporation
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10#include <linux/clk.h>
  11#include <linux/err.h>
  12#include <linux/init.h>
  13#include <linux/module.h>
  14#include <linux/platform_device.h>
  15#include <linux/slab.h>
  16
  17#include <asm/io.h>
  18#include <mach/smc.h>
  19
  20#include "hsmc.h"
  21
  22#define NR_CHIP_SELECTS 6
  23
  24struct hsmc {
  25        void __iomem *regs;
  26        struct clk *pclk;
  27        struct clk *mck;
  28};
  29
  30static struct hsmc *hsmc;
  31
  32void smc_set_timing(struct smc_config *config,
  33                    const struct smc_timing *timing)
  34{
  35        int recover;
  36        int cycle;
  37
  38        unsigned long mul;
  39
  40        /* Reset all SMC timings */
  41        config->ncs_read_setup  = 0;
  42        config->nrd_setup       = 0;
  43        config->ncs_write_setup = 0;
  44        config->nwe_setup       = 0;
  45        config->ncs_read_pulse  = 0;
  46        config->nrd_pulse       = 0;
  47        config->ncs_write_pulse = 0;
  48        config->nwe_pulse       = 0;
  49        config->read_cycle      = 0;
  50        config->write_cycle     = 0;
  51
  52        /*
  53         * cycles = x / T = x * f
  54         *   = ((x * 1000000000) * ((f * 65536) / 1000000000)) / 65536
  55         *   = ((x * 1000000000) * (((f / 10000) * 65536) / 100000)) / 65536
  56         */
  57        mul = (clk_get_rate(hsmc->mck) / 10000) << 16;
  58        mul /= 100000;
  59
  60#define ns2cyc(x) ((((x) * mul) + 65535) >> 16)
  61
  62        if (timing->ncs_read_setup > 0)
  63                config->ncs_read_setup = ns2cyc(timing->ncs_read_setup);
  64
  65        if (timing->nrd_setup > 0)
  66                config->nrd_setup = ns2cyc(timing->nrd_setup);
  67
  68        if (timing->ncs_write_setup > 0)
  69                config->ncs_write_setup = ns2cyc(timing->ncs_write_setup);
  70
  71        if (timing->nwe_setup > 0)
  72                config->nwe_setup = ns2cyc(timing->nwe_setup);
  73
  74        if (timing->ncs_read_pulse > 0)
  75                config->ncs_read_pulse = ns2cyc(timing->ncs_read_pulse);
  76
  77        if (timing->nrd_pulse > 0)
  78                config->nrd_pulse = ns2cyc(timing->nrd_pulse);
  79
  80        if (timing->ncs_write_pulse > 0)
  81                config->ncs_write_pulse = ns2cyc(timing->ncs_write_pulse);
  82
  83        if (timing->nwe_pulse > 0)
  84                config->nwe_pulse = ns2cyc(timing->nwe_pulse);
  85
  86        if (timing->read_cycle > 0)
  87                config->read_cycle = ns2cyc(timing->read_cycle);
  88
  89        if (timing->write_cycle > 0)
  90                config->write_cycle = ns2cyc(timing->write_cycle);
  91
  92        /* Extend read cycle in needed */
  93        if (timing->ncs_read_recover > 0)
  94                recover = ns2cyc(timing->ncs_read_recover);
  95        else
  96                recover = 1;
  97
  98        cycle = config->ncs_read_setup + config->ncs_read_pulse + recover;
  99
 100        if (config->read_cycle < cycle)
 101                config->read_cycle = cycle;
 102
 103        /* Extend read cycle in needed */
 104        if (timing->nrd_recover > 0)
 105                recover = ns2cyc(timing->nrd_recover);
 106        else
 107                recover = 1;
 108
 109        cycle = config->nrd_setup + config->nrd_pulse + recover;
 110
 111        if (config->read_cycle < cycle)
 112                config->read_cycle = cycle;
 113
 114        /* Extend write cycle in needed */
 115        if (timing->ncs_write_recover > 0)
 116                recover = ns2cyc(timing->ncs_write_recover);
 117        else
 118                recover = 1;
 119
 120        cycle = config->ncs_write_setup + config->ncs_write_pulse + recover;
 121
 122        if (config->write_cycle < cycle)
 123                config->write_cycle = cycle;
 124
 125        /* Extend write cycle in needed */
 126        if (timing->nwe_recover > 0)
 127                recover = ns2cyc(timing->nwe_recover);
 128        else
 129                recover = 1;
 130
 131        cycle = config->nwe_setup + config->nwe_pulse + recover;
 132
 133        if (config->write_cycle < cycle)
 134                config->write_cycle = cycle;
 135}
 136EXPORT_SYMBOL(smc_set_timing);
 137
 138int smc_set_configuration(int cs, const struct smc_config *config)
 139{
 140        unsigned long offset;
 141        u32 setup, pulse, cycle, mode;
 142
 143        if (!hsmc)
 144                return -ENODEV;
 145        if (cs >= NR_CHIP_SELECTS)
 146                return -EINVAL;
 147
 148        setup = (HSMC_BF(NWE_SETUP, config->nwe_setup)
 149                 | HSMC_BF(NCS_WR_SETUP, config->ncs_write_setup)
 150                 | HSMC_BF(NRD_SETUP, config->nrd_setup)
 151                 | HSMC_BF(NCS_RD_SETUP, config->ncs_read_setup));
 152        pulse = (HSMC_BF(NWE_PULSE, config->nwe_pulse)
 153                 | HSMC_BF(NCS_WR_PULSE, config->ncs_write_pulse)
 154                 | HSMC_BF(NRD_PULSE, config->nrd_pulse)
 155                 | HSMC_BF(NCS_RD_PULSE, config->ncs_read_pulse));
 156        cycle = (HSMC_BF(NWE_CYCLE, config->write_cycle)
 157                 | HSMC_BF(NRD_CYCLE, config->read_cycle));
 158
 159        switch (config->bus_width) {
 160        case 1:
 161                mode = HSMC_BF(DBW, HSMC_DBW_8_BITS);
 162                break;
 163        case 2:
 164                mode = HSMC_BF(DBW, HSMC_DBW_16_BITS);
 165                break;
 166        case 4:
 167                mode = HSMC_BF(DBW, HSMC_DBW_32_BITS);
 168                break;
 169        default:
 170                return -EINVAL;
 171        }
 172
 173        switch (config->nwait_mode) {
 174        case 0:
 175                mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_DISABLED);
 176                break;
 177        case 1:
 178                mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_RESERVED);
 179                break;
 180        case 2:
 181                mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_FROZEN);
 182                break;
 183        case 3:
 184                mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_READY);
 185                break;
 186        default:
 187                return -EINVAL;
 188        }
 189
 190        if (config->tdf_cycles) {
 191                mode |= HSMC_BF(TDF_CYCLES, config->tdf_cycles);
 192        }
 193
 194        if (config->nrd_controlled)
 195                mode |= HSMC_BIT(READ_MODE);
 196        if (config->nwe_controlled)
 197                mode |= HSMC_BIT(WRITE_MODE);
 198        if (config->byte_write)
 199                mode |= HSMC_BIT(BAT);
 200        if (config->tdf_mode)
 201                mode |= HSMC_BIT(TDF_MODE);
 202
 203        pr_debug("smc cs%d: setup/%08x pulse/%08x cycle/%08x mode/%08x\n",
 204                 cs, setup, pulse, cycle, mode);
 205
 206        offset = cs * 0x10;
 207        hsmc_writel(hsmc, SETUP0 + offset, setup);
 208        hsmc_writel(hsmc, PULSE0 + offset, pulse);
 209        hsmc_writel(hsmc, CYCLE0 + offset, cycle);
 210        hsmc_writel(hsmc, MODE0 + offset, mode);
 211        hsmc_readl(hsmc, MODE0); /* I/O barrier */
 212
 213        return 0;
 214}
 215EXPORT_SYMBOL(smc_set_configuration);
 216
 217static int hsmc_probe(struct platform_device *pdev)
 218{
 219        struct resource *regs;
 220        struct clk *pclk, *mck;
 221        int ret;
 222
 223        if (hsmc)
 224                return -EBUSY;
 225
 226        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 227        if (!regs)
 228                return -ENXIO;
 229        pclk = clk_get(&pdev->dev, "pclk");
 230        if (IS_ERR(pclk))
 231                return PTR_ERR(pclk);
 232        mck = clk_get(&pdev->dev, "mck");
 233        if (IS_ERR(mck)) {
 234                ret = PTR_ERR(mck);
 235                goto out_put_pclk;
 236        }
 237
 238        ret = -ENOMEM;
 239        hsmc = kzalloc(sizeof(struct hsmc), GFP_KERNEL);
 240        if (!hsmc)
 241                goto out_put_clocks;
 242
 243        clk_enable(pclk);
 244        clk_enable(mck);
 245
 246        hsmc->pclk = pclk;
 247        hsmc->mck = mck;
 248        hsmc->regs = ioremap(regs->start, resource_size(regs));
 249        if (!hsmc->regs)
 250                goto out_disable_clocks;
 251
 252        dev_info(&pdev->dev, "Atmel Static Memory Controller at 0x%08lx\n",
 253                 (unsigned long)regs->start);
 254
 255        platform_set_drvdata(pdev, hsmc);
 256
 257        return 0;
 258
 259out_disable_clocks:
 260        clk_disable(mck);
 261        clk_disable(pclk);
 262        kfree(hsmc);
 263out_put_clocks:
 264        clk_put(mck);
 265out_put_pclk:
 266        clk_put(pclk);
 267        hsmc = NULL;
 268        return ret;
 269}
 270
 271static struct platform_driver hsmc_driver = {
 272        .probe          = hsmc_probe,
 273        .driver         = {
 274                .name   = "smc",
 275        },
 276};
 277
 278static int __init hsmc_init(void)
 279{
 280        return platform_driver_register(&hsmc_driver);
 281}
 282core_initcall(hsmc_init);
 283