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#define DEBUG 11#include <linux/clk.h> 12#include <linux/err.h> 13#include <linux/init.h> 14#include <linux/module.h> 15#include <linux/platform_device.h> 16 17#include <asm/io.h> 18#include <asm/arch/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 32int smc_set_configuration(int cs, const struct smc_config *config) 33{ 34 unsigned long mul; 35 unsigned long offset; 36 u32 setup, pulse, cycle, mode; 37 38 if (!hsmc) 39 return -ENODEV; 40 if (cs >= NR_CHIP_SELECTS) 41 return -EINVAL; 42 43 /* 44 * cycles = x / T = x * f 45 * = ((x * 1000000000) * ((f * 65536) / 1000000000)) / 65536 46 * = ((x * 1000000000) * (((f / 10000) * 65536) / 100000)) / 65536 47 */ 48 mul = (clk_get_rate(hsmc->mck) / 10000) << 16; 49 mul /= 100000; 50 51#define ns2cyc(x) ((((x) * mul) + 65535) >> 16) 52 53 setup = (HSMC_BF(NWE_SETUP, ns2cyc(config->nwe_setup)) 54 | HSMC_BF(NCS_WR_SETUP, ns2cyc(config->ncs_write_setup)) 55 | HSMC_BF(NRD_SETUP, ns2cyc(config->nrd_setup)) 56 | HSMC_BF(NCS_RD_SETUP, ns2cyc(config->ncs_read_setup))); 57 pulse = (HSMC_BF(NWE_PULSE, ns2cyc(config->nwe_pulse)) 58 | HSMC_BF(NCS_WR_PULSE, ns2cyc(config->ncs_write_pulse)) 59 | HSMC_BF(NRD_PULSE, ns2cyc(config->nrd_pulse)) 60 | HSMC_BF(NCS_RD_PULSE, ns2cyc(config->ncs_read_pulse))); 61 cycle = (HSMC_BF(NWE_CYCLE, ns2cyc(config->write_cycle)) 62 | HSMC_BF(NRD_CYCLE, ns2cyc(config->read_cycle))); 63 64 switch (config->bus_width) { 65 case 1: 66 mode = HSMC_BF(DBW, HSMC_DBW_8_BITS); 67 break; 68 case 2: 69 mode = HSMC_BF(DBW, HSMC_DBW_16_BITS); 70 break; 71 case 4: 72 mode = HSMC_BF(DBW, HSMC_DBW_32_BITS); 73 break; 74 default: 75 return -EINVAL; 76 } 77 78 switch (config->nwait_mode) { 79 case 0: 80 mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_DISABLED); 81 break; 82 case 1: 83 mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_RESERVED); 84 break; 85 case 2: 86 mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_FROZEN); 87 break; 88 case 3: 89 mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_READY); 90 break; 91 default: 92 return -EINVAL; 93 } 94 95 if (config->tdf_cycles) { 96 mode |= HSMC_BF(TDF_CYCLES, config->tdf_cycles); 97 } 98 99 if (config->nrd_controlled) 100 mode |= HSMC_BIT(READ_MODE); 101 if (config->nwe_controlled) 102 mode |= HSMC_BIT(WRITE_MODE); 103 if (config->byte_write) 104 mode |= HSMC_BIT(BAT); 105 if (config->tdf_mode) 106 mode |= HSMC_BIT(TDF_MODE); 107 108 pr_debug("smc cs%d: setup/%08x pulse/%08x cycle/%08x mode/%08x\n", 109 cs, setup, pulse, cycle, mode); 110 111 offset = cs * 0x10; 112 hsmc_writel(hsmc, SETUP0 + offset, setup); 113 hsmc_writel(hsmc, PULSE0 + offset, pulse); 114 hsmc_writel(hsmc, CYCLE0 + offset, cycle); 115 hsmc_writel(hsmc, MODE0 + offset, mode); 116 hsmc_readl(hsmc, MODE0); /* I/O barrier */ 117 118 return 0; 119} 120EXPORT_SYMBOL(smc_set_configuration); 121 122static int hsmc_probe(struct platform_device *pdev) 123{ 124 struct resource *regs; 125 struct clk *pclk, *mck; 126 int ret; 127 128 if (hsmc) 129 return -EBUSY; 130 131 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 132 if (!regs) 133 return -ENXIO; 134 pclk = clk_get(&pdev->dev, "pclk"); 135 if (IS_ERR(pclk)) 136 return PTR_ERR(pclk); 137 mck = clk_get(&pdev->dev, "mck"); 138 if (IS_ERR(mck)) { 139 ret = PTR_ERR(mck); 140 goto out_put_pclk; 141 } 142 143 ret = -ENOMEM; 144 hsmc = kzalloc(sizeof(struct hsmc), GFP_KERNEL); 145 if (!hsmc) 146 goto out_put_clocks; 147 148 clk_enable(pclk); 149 clk_enable(mck); 150 151 hsmc->pclk = pclk; 152 hsmc->mck = mck; 153 hsmc->regs = ioremap(regs->start, regs->end - regs->start + 1); 154 if (!hsmc->regs) 155 goto out_disable_clocks; 156 157 dev_info(&pdev->dev, "Atmel Static Memory Controller at 0x%08lx\n", 158 (unsigned long)regs->start); 159 160 platform_set_drvdata(pdev, hsmc); 161 162 return 0; 163 164out_disable_clocks: 165 clk_disable(mck); 166 clk_disable(pclk); 167 kfree(hsmc); 168out_put_clocks: 169 clk_put(mck); 170out_put_pclk: 171 clk_put(pclk); 172 hsmc = NULL; 173 return ret; 174} 175 176static struct platform_driver hsmc_driver = { 177 .probe = hsmc_probe, 178 .driver = { 179 .name = "smc", 180 }, 181}; 182 183static int __init hsmc_init(void) 184{ 185 return platform_driver_register(&hsmc_driver); 186} 187arch_initcall(hsmc_init); 188