gpmc-onenand.c 11.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
/*
 * linux/arch/arm/mach-omap2/gpmc-onenand.c
 *
 * Copyright (C) 2006 - 2009 Nokia Corporation
 * Contacts:	Juha Yrjola
 *		Tony Lindgren
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

13
#include <linux/string.h>
14 15 16 17
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/mtd/onenand_regs.h>
#include <linux/io.h>
18
#include <linux/platform_data/mtd-onenand-omap2.h>
19
#include <linux/err.h>
20 21 22

#include <asm/mach/flash.h>

23
#include <plat/gpmc.h>
24

25
#include "soc.h"
26
#include "gpmc-onenand.h"
27

28 29
#define	ONENAND_IO_SIZE	SZ_128K

30 31 32 33 34 35 36 37 38
#define	ONENAND_FLAG_SYNCREAD	(1 << 0)
#define	ONENAND_FLAG_SYNCWRITE	(1 << 1)
#define	ONENAND_FLAG_HF		(1 << 2)
#define	ONENAND_FLAG_VHF	(1 << 3)

static unsigned onenand_flags;
static unsigned latency;
static int fclk_offset;

39 40
static struct omap_onenand_platform_data *gpmc_onenand_data;

41 42 43 44
static struct resource gpmc_onenand_resource = {
	.flags		= IORESOURCE_MEM,
};

45 46 47
static struct platform_device gpmc_onenand_device = {
	.name		= "omap2-onenand",
	.id		= -1,
48 49
	.num_resources	= 1,
	.resource	= &gpmc_onenand_resource,
50 51
};

52
static struct gpmc_timings omap2_onenand_calc_async_timings(void)
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
{
	struct gpmc_timings t;

	const int t_cer = 15;
	const int t_avdp = 12;
	const int t_aavdh = 7;
	const int t_ce = 76;
	const int t_aa = 76;
	const int t_oe = 20;
	const int t_cez = 20; /* max of t_cez, t_oez */
	const int t_ds = 30;
	const int t_wpl = 40;
	const int t_wph = 30;

	memset(&t, 0, sizeof(t));
	t.sync_clk = 0;
	t.cs_on = 0;
	t.adv_on = 0;

	/* Read */
	t.adv_rd_off = gpmc_round_ns_to_ticks(max_t(int, t_avdp, t_cer));
	t.oe_on  = t.adv_rd_off + gpmc_round_ns_to_ticks(t_aavdh);
	t.access = t.adv_on + gpmc_round_ns_to_ticks(t_aa);
	t.access = max_t(int, t.access, t.cs_on + gpmc_round_ns_to_ticks(t_ce));
	t.access = max_t(int, t.access, t.oe_on + gpmc_round_ns_to_ticks(t_oe));
	t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
	t.cs_rd_off = t.oe_off;
	t.rd_cycle  = t.cs_rd_off + gpmc_round_ns_to_ticks(t_cez);

	/* Write */
	t.adv_wr_off = t.adv_rd_off;
	t.we_on  = t.oe_on;
	if (cpu_is_omap34xx()) {
		t.wr_data_mux_bus = t.we_on;
		t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
	}
	t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
	t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph);
	t.wr_cycle  = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);

93 94 95 96 97
	return t;
}

static int gpmc_set_async_mode(int cs, struct gpmc_timings *t)
{
98 99 100 101 102
	/* Configure GPMC for asynchronous read */
	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
			  GPMC_CONFIG1_DEVICESIZE_16 |
			  GPMC_CONFIG1_MUXADDDATA);

103 104 105 106 107 108
	return gpmc_cs_set_timings(cs, t);
}

static void omap2_onenand_set_async_mode(void __iomem *onenand_base)
{
	u32 reg;
109 110 111 112 113

	/* Ensure sync read and sync write are disabled */
	reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
	reg &= ~ONENAND_SYS_CFG1_SYNC_READ & ~ONENAND_SYS_CFG1_SYNC_WRITE;
	writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
114 115
}

116
static void set_onenand_cfg(void __iomem *onenand_base)
117 118 119 120 121 122 123
{
	u32 reg;

	reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
	reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9));
	reg |=	(latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
		ONENAND_SYS_CFG1_BL_16;
124
	if (onenand_flags & ONENAND_FLAG_SYNCREAD)
125 126 127
		reg |= ONENAND_SYS_CFG1_SYNC_READ;
	else
		reg &= ~ONENAND_SYS_CFG1_SYNC_READ;
128
	if (onenand_flags & ONENAND_FLAG_SYNCWRITE)
129 130 131
		reg |= ONENAND_SYS_CFG1_SYNC_WRITE;
	else
		reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE;
132
	if (onenand_flags & ONENAND_FLAG_HF)
133 134 135
		reg |= ONENAND_SYS_CFG1_HF;
	else
		reg &= ~ONENAND_SYS_CFG1_HF;
136
	if (onenand_flags & ONENAND_FLAG_VHF)
137 138 139
		reg |= ONENAND_SYS_CFG1_VHF;
	else
		reg &= ~ONENAND_SYS_CFG1_VHF;
140 141 142
	writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
}

143
static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg,
144
				  void __iomem *onenand_base)
145 146
{
	u16 ver = readw(onenand_base + ONENAND_REG_VERSION_ID);
147
	int freq;
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172

	switch ((ver >> 4) & 0xf) {
	case 0:
		freq = 40;
		break;
	case 1:
		freq = 54;
		break;
	case 2:
		freq = 66;
		break;
	case 3:
		freq = 83;
		break;
	case 4:
		freq = 104;
		break;
	default:
		freq = 54;
		break;
	}

	return freq;
}

173 174
static struct gpmc_timings
omap2_onenand_calc_sync_timings(struct omap_onenand_platform_data *cfg,
175
				int freq)
176 177 178 179 180 181 182 183 184 185
{
	struct gpmc_timings t;
	const int t_cer  = 15;
	const int t_avdp = 12;
	const int t_cez  = 20; /* max of t_cez, t_oez */
	const int t_ds   = 30;
	const int t_wpl  = 40;
	const int t_wph  = 30;
	int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
	u32 reg;
186 187 188
	int div, fclk_offset_ns, gpmc_clk_ns;
	int ticks_cez;
	int cs = cfg->cs;
189

190 191 192 193
	if (cfg->flags & ONENAND_SYNC_READ)
		onenand_flags = ONENAND_FLAG_SYNCREAD;
	else if (cfg->flags & ONENAND_SYNC_READWRITE)
		onenand_flags = ONENAND_FLAG_SYNCREAD | ONENAND_FLAG_SYNCWRITE;
194 195

	switch (freq) {
196 197 198 199 200 201 202
	case 104:
		min_gpmc_clk_period = 9600; /* 104 MHz */
		t_ces   = 3;
		t_avds  = 4;
		t_avdh  = 2;
		t_ach   = 3;
		t_aavdh = 6;
203
		t_rdyo  = 6;
204
		break;
205
	case 83:
206
		min_gpmc_clk_period = 12000; /* 83 MHz */
207 208 209 210 211 212 213 214
		t_ces   = 5;
		t_avds  = 4;
		t_avdh  = 2;
		t_ach   = 6;
		t_aavdh = 6;
		t_rdyo  = 9;
		break;
	case 66:
215
		min_gpmc_clk_period = 15000; /* 66 MHz */
216 217 218 219 220 221 222 223
		t_ces   = 6;
		t_avds  = 5;
		t_avdh  = 2;
		t_ach   = 6;
		t_aavdh = 6;
		t_rdyo  = 11;
		break;
	default:
224
		min_gpmc_clk_period = 18500; /* 54 MHz */
225 226 227 228 229 230
		t_ces   = 7;
		t_avds  = 7;
		t_avdh  = 7;
		t_ach   = 9;
		t_aavdh = 7;
		t_rdyo  = 15;
231
		onenand_flags &= ~ONENAND_FLAG_SYNCWRITE;
232 233 234
		break;
	}

235
	div = gpmc_calc_divider(min_gpmc_clk_period);
236 237
	gpmc_clk_ns = gpmc_ticks_to_ns(div);
	if (gpmc_clk_ns < 15) /* >66Mhz */
238 239 240
		onenand_flags |= ONENAND_FLAG_HF;
	else
		onenand_flags &= ~ONENAND_FLAG_HF;
241
	if (gpmc_clk_ns < 12) /* >83Mhz */
242 243 244 245
		onenand_flags |= ONENAND_FLAG_VHF;
	else
		onenand_flags &= ~ONENAND_FLAG_VHF;
	if (onenand_flags & ONENAND_FLAG_VHF)
246
		latency = 8;
247
	else if (onenand_flags & ONENAND_FLAG_HF)
248 249 250 251 252 253
		latency = 6;
	else if (gpmc_clk_ns >= 25) /* 40 MHz*/
		latency = 3;
	else
		latency = 4;

254 255
	/* Set synchronous read timings */
	memset(&t, 0, sizeof(t));
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290

	if (div == 1) {
		reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
		reg |= (1 << 7);
		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg);
		reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
		reg |= (1 << 7);
		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg);
		reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
		reg |= (1 << 7);
		reg |= (1 << 23);
		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
	} else {
		reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
		reg &= ~(1 << 7);
		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg);
		reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
		reg &= ~(1 << 7);
		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg);
		reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
		reg &= ~(1 << 7);
		reg &= ~(1 << 23);
		gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
	}

	t.sync_clk = min_gpmc_clk_period;
	t.cs_on = 0;
	t.adv_on = 0;
	fclk_offset_ns = gpmc_round_ns_to_ticks(max_t(int, t_ces, t_avds));
	fclk_offset = gpmc_ns_to_ticks(fclk_offset_ns);
	t.page_burst_access = gpmc_clk_ns;

	/* Read */
	t.adv_rd_off = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_avdh));
	t.oe_on = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_ach));
291 292 293
	/* Force at least 1 clk between AVD High to OE Low */
	if (t.oe_on <= t.adv_rd_off)
		t.oe_on = t.adv_rd_off + gpmc_round_ns_to_ticks(1);
294 295 296 297 298 299 300 301
	t.access = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div);
	t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
	t.cs_rd_off = t.oe_off;
	ticks_cez = ((gpmc_ns_to_ticks(t_cez) + div - 1) / div) * div;
	t.rd_cycle = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div +
		     ticks_cez);

	/* Write */
302
	if (onenand_flags & ONENAND_FLAG_SYNCWRITE) {
303 304 305 306 307 308 309
		t.adv_wr_off = t.adv_rd_off;
		t.we_on  = 0;
		t.we_off = t.cs_rd_off;
		t.cs_wr_off = t.cs_rd_off;
		t.wr_cycle  = t.rd_cycle;
		if (cpu_is_omap34xx()) {
			t.wr_data_mux_bus = gpmc_ticks_to_ns(fclk_offset +
310 311
					gpmc_ps_to_ticks(min_gpmc_clk_period +
					t_rdyo * 1000));
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
			t.wr_access = t.access;
		}
	} else {
		t.adv_wr_off = gpmc_round_ns_to_ticks(max_t(int,
							t_avdp, t_cer));
		t.we_on  = t.adv_wr_off + gpmc_round_ns_to_ticks(t_aavdh);
		t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
		t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph);
		t.wr_cycle  = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);
		if (cpu_is_omap34xx()) {
			t.wr_data_mux_bus = t.we_on;
			t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
		}
	}

327 328 329 330 331 332 333 334
	return t;
}

static int gpmc_set_sync_mode(int cs, struct gpmc_timings *t)
{
	unsigned sync_read = onenand_flags & ONENAND_FLAG_SYNCREAD;
	unsigned sync_write = onenand_flags & ONENAND_FLAG_SYNCWRITE;

335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
	/* Configure GPMC for synchronous read */
	gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
			  GPMC_CONFIG1_WRAPBURST_SUPP |
			  GPMC_CONFIG1_READMULTIPLE_SUPP |
			  (sync_read ? GPMC_CONFIG1_READTYPE_SYNC : 0) |
			  (sync_write ? GPMC_CONFIG1_WRITEMULTIPLE_SUPP : 0) |
			  (sync_write ? GPMC_CONFIG1_WRITETYPE_SYNC : 0) |
			  GPMC_CONFIG1_CLKACTIVATIONTIME(fclk_offset) |
			  GPMC_CONFIG1_PAGE_LEN(2) |
			  (cpu_is_omap34xx() ? 0 :
				(GPMC_CONFIG1_WAIT_READ_MON |
				 GPMC_CONFIG1_WAIT_PIN_SEL(0))) |
			  GPMC_CONFIG1_DEVICESIZE_16 |
			  GPMC_CONFIG1_DEVICETYPE_NOR |
			  GPMC_CONFIG1_MUXADDDATA);

351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
	return gpmc_cs_set_timings(cs, t);
}

static int omap2_onenand_setup_async(void __iomem *onenand_base)
{
	struct gpmc_timings t;
	int ret;

	omap2_onenand_set_async_mode(onenand_base);

	t = omap2_onenand_calc_async_timings();

	ret = gpmc_set_async_mode(gpmc_onenand_data->cs, &t);
	if (IS_ERR_VALUE(ret))
		return ret;

	omap2_onenand_set_async_mode(onenand_base);

	return 0;
}

static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr)
{
	int ret, freq = *freq_ptr;
	struct gpmc_timings t;

	if (!freq) {
		/* Very first call freq is not known */
379
		freq = omap2_onenand_get_freq(gpmc_onenand_data, onenand_base);
380 381 382
		set_onenand_cfg(onenand_base);
	}

383
	t = omap2_onenand_calc_sync_timings(gpmc_onenand_data, freq);
384

385 386 387 388 389
	ret = gpmc_set_sync_mode(gpmc_onenand_data->cs, &t);
	if (IS_ERR_VALUE(ret))
		return ret;

	set_onenand_cfg(onenand_base);
390

391 392
	*freq_ptr = freq;

393 394 395
	return 0;
}

396
static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr)
397 398
{
	struct device *dev = &gpmc_onenand_device.dev;
399 400
	unsigned l = ONENAND_SYNC_READ | ONENAND_SYNC_READWRITE;
	int ret;
401

402 403 404 405
	ret = omap2_onenand_setup_async(onenand_base);
	if (ret) {
		dev_err(dev, "unable to set to async mode\n");
		return ret;
406 407
	}

408 409 410 411 412 413 414
	if (!(gpmc_onenand_data->flags & l))
		return 0;

	ret = omap2_onenand_setup_sync(onenand_base, freq_ptr);
	if (ret)
		dev_err(dev, "unable to set to sync mode\n");
	return ret;
415 416 417 418
}

void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data)
{
419 420
	int err;

421 422 423 424 425 426 427 428 429 430 431
	gpmc_onenand_data = _onenand_data;
	gpmc_onenand_data->onenand_setup = gpmc_onenand_setup;
	gpmc_onenand_device.dev.platform_data = gpmc_onenand_data;

	if (cpu_is_omap24xx() &&
			(gpmc_onenand_data->flags & ONENAND_SYNC_READWRITE)) {
		printk(KERN_ERR "Onenand using only SYNC_READ on 24xx\n");
		gpmc_onenand_data->flags &= ~ONENAND_SYNC_READWRITE;
		gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
	}

432 433 434 435 436
	if (cpu_is_omap34xx())
		gpmc_onenand_data->flags |= ONENAND_IN_OMAP34XX;
	else
		gpmc_onenand_data->flags &= ~ONENAND_IN_OMAP34XX;

437 438 439 440 441 442 443 444 445 446
	err = gpmc_cs_request(gpmc_onenand_data->cs, ONENAND_IO_SIZE,
				(unsigned long *)&gpmc_onenand_resource.start);
	if (err < 0) {
		pr_err("%s: Cannot request GPMC CS\n", __func__);
		return;
	}

	gpmc_onenand_resource.end = gpmc_onenand_resource.start +
							ONENAND_IO_SIZE - 1;

447
	if (platform_device_register(&gpmc_onenand_device) < 0) {
448 449
		pr_err("%s: Unable to register OneNAND device\n", __func__);
		gpmc_cs_free(gpmc_onenand_data->cs);
450 451 452
		return;
	}
}