summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap/gpmc.c
blob: 5b4daaf031303a1a755cf29f51388af89fe2a5e1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/**
 * @file
 * @brief Provide Generic GPMC configuration option
 *
 * FileName: arch/arm/mach-omap/gpmc.c
 *
 * This file contains the generic GPMC implementation
 *
 */
/*
 * (C) Copyright 2008
 * Texas Instruments, <www.ti.com>
 * Nishanth Menon <x0nishan@ti.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */
#include <common.h>
#include <clock.h>
#include <init.h>
#include <io.h>
#include <errno.h>
#include <mach/silicon.h>
#include <mach/gpmc.h>
#include <mach/sys_info.h>
#include <mach/syslib.h>

/**
 * @brief Do a Generic initialization of GPMC. if you choose otherwise,
 * Use gpmc registers to modify the values. The defaults configured are:
 * No idle, L3 free running, no timeout and no IRQs.
 * we allow for gpmc_config data to be programmed, and will also disable
 * ALL CS configurations
 *
 * @param cfg - GPMC_CFG register value
 *
 * @return void
 */
void gpmc_generic_init(unsigned int cfg)
{
	uint64_t start;
	unsigned int reg = GPMC_REG(CONFIG7_0);
	char x = 0;

	debug("gpmccfg=%x\n", cfg);
	/* Generic Configurations */
	/* reset gpmc */
	start = get_time_ns();
	/* No idle, L3 clock free running */
	writel(0x12, GPMC_REG(SYS_CONFIG));
	while (!readl(GPMC_REG(SYS_STATUS)))
		if (is_timeout(start, MSECOND)) {
			printf("timeout on gpmc reset\n");
			break;
		}

	/* No Timeout */
	writel(0x00, GPMC_REG(TIMEOUT_CONTROL));
	/* No IRQs */
	writel(0x00, GPMC_REG(IRQ_ENABLE));
	/* Write the gpmc_config value */
	writel(cfg, GPMC_REG(CFG));

	/* Disable all CS - prevents remaps
	 * But NEVER run me in XIP mode! I will Die!
	 */
	while (x < GPMC_NUM_CS) {
		debug("gpmccs=%d Reg:%x <-0x0\n", x, reg);
		writel(0x0, reg);
		reg += GPMC_CONFIG_CS_SIZE;
		x++;
	}
	/* Give me a while to settle things down */
	mdelay(1);
}
EXPORT_SYMBOL(gpmc_generic_init);

/**
 * @brief Configure the registers and enable a single CS.
 *
 * @param cs chip select index
 * @param config gpmc_config structure describing the CS params
 *
 * @return void
 */
void gpmc_cs_config(char cs, struct gpmc_config *config)
{
	unsigned int reg = GPMC_REG(CONFIG1_0) + (cs * GPMC_CONFIG_CS_SIZE);
	unsigned char x = 0;
	debug("gpmccs=%x cfg=%x\n", cs, (unsigned int)config);

	/* Disable the CS before reconfiguring */
	writel(0x0, GPMC_REG(CONFIG7_0) + (cs * GPMC_CONFIG_CS_SIZE));
	mdelay(1);		/* Settling time */

	/* Write the CFG1-6 regs */
	while (x < 6) {
		debug("gpmccfg=%d Reg:%x <-0x%x\n",
				x, reg, config->cfg[x]);
		writel(config->cfg[x], reg);
		reg += GPMC_CONFIG_REG_OFF;
		x++;
	}
	/* reg now points to CFG7 */
	debug("gpmccfg=%d Reg:%x <-0x%x\n",
			x, reg, (0x1 << 6) |		/* CS enable */
		     ((config->size & 0xF) << 8) |	/* Size */
		     ((config->base >> 24) & 0x3F));

	writel((0x1 << 6) |			/* CS enable */
		     ((config->size & 0xF) << 8) |	/* Size */
		     ((config->base >> 24) & 0x3F),	/* Address */
		     reg);
	mdelay(1);		/* Settling time */
}
EXPORT_SYMBOL(gpmc_cs_config);

#define CS_NUM_SHIFT		24
#define ENABLE_PREFETCH		(0x1 << 7)
#define DMA_MPU_MODE		2

/**
 * gpmc_prefetch_enable - configures and starts prefetch transfer
 * @cs: cs (chip select) number
 * @fifo_th: fifo threshold to be used for read/ write
 * @dma_mode: dma mode enable (1) or disable (0)
 * @u32_count: number of bytes to be transferred
 * @is_write: prefetch read(0) or write post(1) mode
 */
int gpmc_prefetch_enable(int cs, int fifo_th, int dma_mode,
				unsigned int u32_count, int is_write)
{
	if (fifo_th > PREFETCH_FIFOTHRESHOLD_MAX) {
		pr_err("gpmc: fifo threshold is not supported\n");
		return -EINVAL;
	}

	/* Set the amount of bytes to be prefetched */
	writel(u32_count, GPMC_REG(PREFETCH_CONFIG2));

	/* Set dma/mpu mode, the prefetch read / post write and
	 * enable the engine. Set which cs is has requested for.
	 */
	writel(((cs << CS_NUM_SHIFT) | PREFETCH_FIFOTHRESHOLD(fifo_th) |
				ENABLE_PREFETCH | (dma_mode << DMA_MPU_MODE) |
				(0x1 & is_write)),
			GPMC_REG(PREFETCH_CONFIG1));

	/*  Start the prefetch engine */
	writel(0x1, GPMC_REG(PREFETCH_CONTROL));

	return 0;
}
EXPORT_SYMBOL(gpmc_prefetch_enable);

/**
 * gpmc_prefetch_reset - disables and stops the prefetch engine
 */
int gpmc_prefetch_reset(int cs)
{
	u32 config1;

	/* check if the same module/cs is trying to reset */
	config1 = readl(GPMC_REG(PREFETCH_CONFIG1));
	if (((config1 >> CS_NUM_SHIFT) & 0x7) != cs)
		return -EINVAL;

	/* Stop the PFPW engine */
	writel(0x0, GPMC_REG(PREFETCH_CONTROL));

	/* Reset/disable the PFPW engine */
	writel(0x0, GPMC_REG(PREFETCH_CONFIG1));

	return 0;
}
EXPORT_SYMBOL(gpmc_prefetch_reset);