~ubuntu-branches/ubuntu/maverick/u-boot-omap3/maverick

« back to all changes in this revision

Viewing changes to drivers/mmc/bfin_sdh.c

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Grawert
  • Date: 2010-03-22 15:06:23 UTC
  • Revision ID: james.westby@ubuntu.com-20100322150623-i21g8rgiyl5dohag
Tags: upstream-2010.3git20100315
ImportĀ upstreamĀ versionĀ 2010.3git20100315

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Driver for Blackfin on-chip SDH controller
 
3
 *
 
4
 * Copyright (c) 2008-2009 Analog Devices Inc.
 
5
 *
 
6
 * Licensed under the GPL-2 or later.
 
7
 */
 
8
 
 
9
#include <common.h>
 
10
#include <malloc.h>
 
11
#include <part.h>
 
12
#include <mmc.h>
 
13
 
 
14
#include <asm/io.h>
 
15
#include <asm/errno.h>
 
16
#include <asm/byteorder.h>
 
17
#include <asm/blackfin.h>
 
18
#include <asm/mach-common/bits/sdh.h>
 
19
#include <asm/mach-common/bits/dma.h>
 
20
 
 
21
#if defined(__ADSPBF51x__)
 
22
# define bfin_read_SDH_PWR_CTL          bfin_read_RSI_PWR_CONTROL
 
23
# define bfin_write_SDH_PWR_CTL         bfin_write_RSI_PWR_CONTROL
 
24
# define bfin_read_SDH_CLK_CTL          bfin_read_RSI_CLK_CONTROL
 
25
# define bfin_write_SDH_CLK_CTL         bfin_write_RSI_CLK_CONTROL
 
26
# define bfin_write_SDH_ARGUMENT        bfin_write_RSI_ARGUMENT
 
27
# define bfin_write_SDH_COMMAND         bfin_write_RSI_COMMAND
 
28
# define bfin_read_SDH_RESPONSE0        bfin_read_RSI_RESPONSE0
 
29
# define bfin_read_SDH_RESPONSE1        bfin_read_RSI_RESPONSE1
 
30
# define bfin_read_SDH_RESPONSE2        bfin_read_RSI_RESPONSE2
 
31
# define bfin_read_SDH_RESPONSE3        bfin_read_RSI_RESPONSE3
 
32
# define bfin_write_SDH_DATA_TIMER      bfin_write_RSI_DATA_TIMER
 
33
# define bfin_write_SDH_DATA_LGTH       bfin_write_RSI_DATA_LGTH
 
34
# define bfin_read_SDH_DATA_CTL         bfin_read_RSI_DATA_CONTROL
 
35
# define bfin_write_SDH_DATA_CTL        bfin_write_RSI_DATA_CONTROL
 
36
# define bfin_read_SDH_STATUS           bfin_read_RSI_STATUS
 
37
# define bfin_write_SDH_STATUS_CLR      bfin_write_RSI_STATUSCL
 
38
# define bfin_read_SDH_CFG              bfin_read_RSI_CONFIG
 
39
# define bfin_write_SDH_CFG             bfin_write_RSI_CONFIG
 
40
# define bfin_write_DMA_START_ADDR      bfin_write_DMA4_START_ADDR
 
41
# define bfin_write_DMA_X_COUNT         bfin_write_DMA4_X_COUNT
 
42
# define bfin_write_DMA_X_MODIFY        bfin_write_DMA4_X_MODIFY
 
43
# define bfin_write_DMA_CONFIG          bfin_write_DMA4_CONFIG
 
44
#elif defined(__ADSPBF54x__)
 
45
# define bfin_write_DMA_START_ADDR      bfin_write_DMA22_START_ADDR
 
46
# define bfin_write_DMA_X_COUNT         bfin_write_DMA22_X_COUNT
 
47
# define bfin_write_DMA_X_MODIFY        bfin_write_DMA22_X_MODIFY
 
48
# define bfin_write_DMA_CONFIG          bfin_write_DMA22_CONFIG
 
49
#else
 
50
# error no support for this proc yet
 
51
#endif
 
52
 
 
53
static int
 
54
sdh_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
 
55
{
 
56
        unsigned int sdh_cmd;
 
57
        unsigned int status;
 
58
        int cmd = mmc_cmd->cmdidx;
 
59
        int flags = mmc_cmd->resp_type;
 
60
        int arg = mmc_cmd->cmdarg;
 
61
        int ret = 0;
 
62
        sdh_cmd = 0;
 
63
 
 
64
        sdh_cmd |= cmd;
 
65
 
 
66
        if (flags & MMC_RSP_PRESENT)
 
67
                sdh_cmd |= CMD_RSP;
 
68
 
 
69
        if (flags & MMC_RSP_136)
 
70
                sdh_cmd |= CMD_L_RSP;
 
71
 
 
72
        bfin_write_SDH_ARGUMENT(arg);
 
73
        bfin_write_SDH_COMMAND(sdh_cmd | CMD_E);
 
74
 
 
75
        /* wait for a while */
 
76
        do {
 
77
                udelay(1);
 
78
                status = bfin_read_SDH_STATUS();
 
79
        } while (!(status & (CMD_SENT | CMD_RESP_END | CMD_TIME_OUT |
 
80
                CMD_CRC_FAIL)));
 
81
 
 
82
        if (flags & MMC_RSP_PRESENT) {
 
83
                mmc_cmd->response[0] = bfin_read_SDH_RESPONSE0();
 
84
                if (flags & MMC_RSP_136) {
 
85
                        mmc_cmd->response[1] = bfin_read_SDH_RESPONSE1();
 
86
                        mmc_cmd->response[2] = bfin_read_SDH_RESPONSE2();
 
87
                        mmc_cmd->response[3] = bfin_read_SDH_RESPONSE3();
 
88
                }
 
89
        }
 
90
 
 
91
        if (status & CMD_TIME_OUT)
 
92
                ret |= TIMEOUT;
 
93
        else if (status & CMD_CRC_FAIL && flags & MMC_RSP_CRC)
 
94
                ret |= COMM_ERR;
 
95
 
 
96
        bfin_write_SDH_STATUS_CLR(CMD_SENT_STAT | CMD_RESP_END_STAT |
 
97
                                CMD_TIMEOUT_STAT | CMD_CRC_FAIL_STAT);
 
98
        return ret;
 
99
}
 
100
 
 
101
/* set data for single block transfer */
 
102
static int sdh_setup_data(struct mmc *mmc, struct mmc_data *data)
 
103
{
 
104
        u16 data_ctl = 0;
 
105
        u16 dma_cfg = 0;
 
106
        int ret = 0;
 
107
 
 
108
        /* Don't support write yet. */
 
109
        if (data->flags & MMC_DATA_WRITE)
 
110
                return UNUSABLE_ERR;
 
111
        data_ctl |= ((ffs(data->blocksize) - 1) << 4);
 
112
        data_ctl |= DTX_DIR;
 
113
        bfin_write_SDH_DATA_CTL(data_ctl);
 
114
        dma_cfg = WDSIZE_32 | RESTART | WNR | DMAEN;
 
115
 
 
116
        bfin_write_SDH_DATA_TIMER(0xFFFF);
 
117
 
 
118
        blackfin_dcache_flush_invalidate_range(data->dest,
 
119
                        data->dest + data->blocksize);
 
120
        /* configure DMA */
 
121
        bfin_write_DMA_START_ADDR(data->dest);
 
122
        bfin_write_DMA_X_COUNT(data->blocksize / 4);
 
123
        bfin_write_DMA_X_MODIFY(4);
 
124
        bfin_write_DMA_CONFIG(dma_cfg);
 
125
        bfin_write_SDH_DATA_LGTH(data->blocksize);
 
126
        /* kick off transfer */
 
127
        bfin_write_SDH_DATA_CTL(bfin_read_SDH_DATA_CTL() | DTX_DMA_E | DTX_E);
 
128
 
 
129
        return ret;
 
130
}
 
131
 
 
132
 
 
133
static int bfin_sdh_request(struct mmc *mmc, struct mmc_cmd *cmd,
 
134
                struct mmc_data *data)
 
135
{
 
136
        u32 status;
 
137
        int ret = 0;
 
138
 
 
139
        ret = sdh_send_cmd(mmc, cmd);
 
140
        if (ret) {
 
141
                printf("sending CMD%d failed\n", cmd->cmdidx);
 
142
                return ret;
 
143
        }
 
144
        if (data) {
 
145
                ret = sdh_setup_data(mmc, data);
 
146
                do {
 
147
                        udelay(1);
 
148
                        status = bfin_read_SDH_STATUS();
 
149
                } while (!(status & (DAT_BLK_END | DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL | RX_OVERRUN)));
 
150
 
 
151
                if (status & DAT_TIME_OUT) {
 
152
                        bfin_write_SDH_STATUS_CLR(DAT_TIMEOUT_STAT);
 
153
                        ret |= TIMEOUT;
 
154
                } else if (status & (DAT_CRC_FAIL | RX_OVERRUN)) {
 
155
                        bfin_write_SDH_STATUS_CLR(DAT_CRC_FAIL_STAT | RX_OVERRUN_STAT);
 
156
                        ret |= COMM_ERR;
 
157
                } else
 
158
                        bfin_write_SDH_STATUS_CLR(DAT_BLK_END_STAT | DAT_END_STAT);
 
159
 
 
160
                if (ret) {
 
161
                        printf("tranfering data failed\n");
 
162
                        return ret;
 
163
                }
 
164
        }
 
165
        return 0;
 
166
}
 
167
 
 
168
static void sdh_set_clk(unsigned long clk)
 
169
{
 
170
        unsigned long sys_clk;
 
171
        unsigned long clk_div;
 
172
        u16 clk_ctl = 0;
 
173
 
 
174
        clk_ctl = bfin_read_SDH_CLK_CTL();
 
175
        if (clk) {
 
176
                /* setting SD_CLK */
 
177
                sys_clk = get_sclk();
 
178
                bfin_write_SDH_CLK_CTL(clk_ctl & ~CLK_E);
 
179
                if (sys_clk % (2 * clk) == 0)
 
180
                        clk_div = sys_clk / (2 * clk) - 1;
 
181
                else
 
182
                        clk_div = sys_clk / (2 * clk);
 
183
 
 
184
                if (clk_div > 0xff)
 
185
                        clk_div = 0xff;
 
186
                clk_ctl |= (clk_div & 0xff);
 
187
                clk_ctl |= CLK_E;
 
188
                bfin_write_SDH_CLK_CTL(clk_ctl);
 
189
        } else
 
190
                bfin_write_SDH_CLK_CTL(clk_ctl & ~CLK_E);
 
191
}
 
192
 
 
193
static void bfin_sdh_set_ios(struct mmc *mmc)
 
194
{
 
195
        u16 cfg = 0;
 
196
        u16 clk_ctl = 0;
 
197
 
 
198
        if (mmc->bus_width == 4) {
 
199
                cfg = bfin_read_SDH_CFG();
 
200
                cfg &= ~0x80;
 
201
                cfg |= 0x40;
 
202
                bfin_write_SDH_CFG(cfg);
 
203
                clk_ctl |= WIDE_BUS;
 
204
        }
 
205
        bfin_write_SDH_CLK_CTL(clk_ctl);
 
206
        sdh_set_clk(mmc->clock);
 
207
}
 
208
 
 
209
static int bfin_sdh_init(struct mmc *mmc)
 
210
{
 
211
 
 
212
        u16 pwr_ctl = 0;
 
213
/* Initialize sdh controller */
 
214
#if defined(__ADSPBF54x__)
 
215
        bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1);
 
216
        bfin_write_PORTC_FER(bfin_read_PORTC_FER() | 0x3F00);
 
217
        bfin_write_PORTC_MUX(bfin_read_PORTC_MUX() & ~0xFFF0000);
 
218
#elif defined(__ADSPBF51x__)
 
219
        bfin_write_PORTG_FER(bfin_read_PORTG_FER() | 0x01F8);
 
220
        bfin_write_PORTG_MUX((bfin_read_PORTG_MUX() & ~0x3FC) | 0x154);
 
221
#else
 
222
# error no portmux for this proc yet
 
223
#endif
 
224
        bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN);
 
225
        /* Disable card detect pin */
 
226
        bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | 0x60);
 
227
 
 
228
        pwr_ctl |= ROD_CTL;
 
229
        pwr_ctl |= PWR_ON;
 
230
        bfin_write_SDH_PWR_CTL(pwr_ctl);
 
231
        return 0;
 
232
}
 
233
 
 
234
 
 
235
int bfin_mmc_init(bd_t *bis)
 
236
{
 
237
        struct mmc *mmc = NULL;
 
238
 
 
239
        mmc = malloc(sizeof(struct mmc));
 
240
 
 
241
        if (!mmc)
 
242
                return -ENOMEM;
 
243
        sprintf(mmc->name, "Blackfin SDH");
 
244
        mmc->send_cmd = bfin_sdh_request;
 
245
        mmc->set_ios = bfin_sdh_set_ios;
 
246
        mmc->init = bfin_sdh_init;
 
247
        mmc->host_caps = MMC_MODE_4BIT;
 
248
 
 
249
        mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
 
250
        mmc->f_max = get_sclk();
 
251
        mmc->f_min = mmc->f_max >> 9;
 
252
        mmc->block_dev.part_type = PART_TYPE_DOS;
 
253
 
 
254
        mmc_register(mmc);
 
255
 
 
256
        return 0;
 
257
}