Root/qiboot/src/cpu/s3c6410/hs_mmc.c

1#include <qi.h>
2#include "hs_mmc.h"
3#include <string.h>
4#include <glamo-mmc.h>
5
6#define HCLK_OPERATION
7#undef DEBUG_HSMMC
8#ifdef DEBUG_HSMMC
9#define dbg(x...) printf(x)
10#else
11#define dbg(x...) do { } while (0)
12#endif
13
14//#include <linux-mmc.h>
15#include <linux-mmc-protocol.h>
16#include <s3c6410.h>
17//#include <linux/mmc/protocol.h>
18//#include <asm/io.h>
19//#include <movi.h>
20
21#include "hs_mmc.h"
22#include <mmc.h>
23
24#define SDI_Tx_buffer_HSMMC (0x51000000)
25#define SDI_Rx_buffer_HSMMC (0x51000000+(0x300000))
26#define SDI_Compare_buffer_HSMMC (0x51000000+(0x600000))
27
28#define Card_OneBlockSize_ver1 512
29
30#define MMC_DEFAULT_RCA (1<<16)
31
32/* Global variables */
33
34static u32 HS_DMA_END = 0;
35static u32 rca = 0;
36
37static ulong HCLK;
38
39int movi_hc = 1; /* sdhc style block indexing */
40enum card_type card_type;
41
42/* extern functions */
43extern ulong get_HCLK(void);
44
45
46#define s3c_hsmmc_readl(x) *((unsigned int *)(((ELFIN_HSMMC_BASE + (HSMMC_CHANNEL * 0x100000)) + (x))))
47#define s3c_hsmmc_readw(x) *((unsigned short *)(((ELFIN_HSMMC_BASE + (HSMMC_CHANNEL * 0x100000)) + (x))))
48#define s3c_hsmmc_readb(x) *((unsigned char *)(((ELFIN_HSMMC_BASE + (HSMMC_CHANNEL * 0x100000)) + (x))))
49
50#define s3c_hsmmc_writel(v,x) *((unsigned int *) (((ELFIN_HSMMC_BASE + (HSMMC_CHANNEL * 0x100000)) + (x)))) = v
51#define s3c_hsmmc_writew(v,x) *((unsigned short *)(((ELFIN_HSMMC_BASE + (HSMMC_CHANNEL * 0x100000)) + (x)))) = v
52#define s3c_hsmmc_writeb(v,x) *((unsigned char *)(((ELFIN_HSMMC_BASE + (HSMMC_CHANNEL * 0x100000)) + (x)))) = v
53
54#define readl(x) *((unsigned int *)(x))
55#define writel(v, x) *((unsigned int *)(x)) = v
56
57#define UNSTUFF_BITS(resp,start,size) \
58        ({ \
59                const int __size = size; \
60                const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \
61                const int __off = 3 - ((start) / 32); \
62                const int __shft = (start) & 31; \
63                u32 __res; \
64                                                                        \
65                __res = resp[__off] >> __shft; \
66                if (__size + __shft > 32) \
67                        __res |= resp[__off-1] << ((32 - __shft) & 31); \
68                __res & __mask; \
69        })
70
71static int wait_for_cmd_done (void)
72{
73    u32 i;
74    ushort n_int, e_int;
75
76    dbg("wait_for_cmd_done\n");
77    for (i = 0; i < 0x20000000; i++) {
78        n_int = s3c_hsmmc_readw(HM_NORINTSTS);
79        dbg(" HM_NORINTSTS: %04x\n", n_int);
80        if (n_int & 0x8000)
81            /* any error */
82            break;
83        if (n_int & 0x0001)
84            /* command complete */
85            return 0;
86    }
87
88    e_int = s3c_hsmmc_readw(HM_ERRINTSTS);
89    s3c_hsmmc_writew(e_int, HM_ERRINTSTS);
90    s3c_hsmmc_writew(n_int, HM_NORINTSTS);
91    puts("cmd error1: 0x");
92    print32(e_int);
93    puts(", HM_NORINTSTS: 0x");
94    print32(n_int);
95    puts("\n");
96
97    return -1;
98}
99
100
101static void ClearCommandCompleteStatus(void)
102{
103    s3c_hsmmc_writew(1 << 0, HM_NORINTSTS);
104    while (s3c_hsmmc_readw(HM_NORINTSTS) & 0x1) {
105        s3c_hsmmc_writew(1 << 0, HM_NORINTSTS);
106    }
107}
108
109static void card_irq_enable(ushort temp)
110{
111    s3c_hsmmc_writew((s3c_hsmmc_readw(HM_NORINTSTSEN) & 0xFEFF) | (temp << 8), HM_NORINTSTSEN);
112}
113
114void hsmmc_reset (void)
115{
116    s3c_hsmmc_writeb(0x3, HM_SWRST);
117}
118
119void hsmmc_set_gpio (void)
120{
121    u32 reg;
122
123    reg = readl(GPGCON) & 0xf0000000;
124    writel(reg | 0x02222222, GPGCON);
125
126    reg = readl(GPGPUD) & 0xfffff000;
127    writel(reg, GPGPUD);
128}
129
130static void set_transfer_mode_register (u32 MultiBlk, u32 DataDirection, u32 AutoCmd12En, u32 BlockCntEn, u32 DmaEn)
131{
132    s3c_hsmmc_writew((s3c_hsmmc_readw(HM_TRNMOD) & ~(0xffff)) | (MultiBlk << 5)
133        | (DataDirection << 4) | (AutoCmd12En << 2)
134        | (BlockCntEn << 1) | (DmaEn << 0), HM_TRNMOD);
135// dbg("\nHM_TRNMOD = 0x%04x\n", HM_TRNMOD);
136}
137
138static void set_arg_register (u32 arg)
139{
140    s3c_hsmmc_writel(arg, HM_ARGUMENT);
141}
142
143static void set_blkcnt_register(ushort uBlkCnt)
144{
145    s3c_hsmmc_writew(uBlkCnt, HM_BLKCNT);
146}
147
148static void SetSystemAddressReg(u32 SysAddr)
149{
150    s3c_hsmmc_writel(SysAddr, HM_SYSAD);
151}
152
153static void set_blksize_register(ushort uDmaBufBoundary, ushort uBlkSize)
154{
155    s3c_hsmmc_writew((uDmaBufBoundary << 12) | (uBlkSize), HM_BLKSIZE);
156}
157
158static void ClearErrInterruptStatus(void)
159{
160    while (s3c_hsmmc_readw(HM_NORINTSTS) & (0x1 << 15)) {
161        s3c_hsmmc_writew(s3c_hsmmc_readw(HM_NORINTSTS), HM_NORINTSTS);
162        s3c_hsmmc_writew(s3c_hsmmc_readw(HM_ERRINTSTS), HM_ERRINTSTS);
163    }
164}
165
166static void InterruptEnable(ushort NormalIntEn, ushort ErrorIntEn)
167{
168    ClearErrInterruptStatus();
169    s3c_hsmmc_writew(NormalIntEn, HM_NORINTSTSEN);
170    s3c_hsmmc_writew(ErrorIntEn, HM_ERRINTSTSEN);
171}
172
173static void hsmmc_clock_onoff (int on)
174{
175    u16 reg16;
176
177    if (on == 0) {
178        reg16 = s3c_hsmmc_readw(HM_CLKCON) & ~(0x1<<2);
179        s3c_hsmmc_writew(reg16, HM_CLKCON);
180    } else {
181        reg16 = s3c_hsmmc_readw(HM_CLKCON);
182        s3c_hsmmc_writew(reg16 | (0x1<<2), HM_CLKCON);
183
184        while (1) {
185            reg16 = s3c_hsmmc_readw(HM_CLKCON);
186            if (reg16 & (0x1<<3)) /* SD_CLKSRC is Stable */
187                break;
188        }
189    }
190}
191
192static void set_clock (u32 clksrc, u32 div)
193{
194    u16 reg16;
195    u32 i;
196
197    s3c_hsmmc_writel(0xC0004100 | (clksrc << 4), HM_CONTROL2); // rx feedback control
198    s3c_hsmmc_writel(0x00008080, HM_CONTROL3); // Low clock: 00008080
199    s3c_hsmmc_writel(0x3 << 16, HM_CONTROL4);
200
201    s3c_hsmmc_writew(s3c_hsmmc_readw(HM_CLKCON) & ~(0xff << 8), HM_CLKCON);
202
203    /* SDCLK Value Setting + Internal Clock Enable */
204    s3c_hsmmc_writew(((div<<8) | 0x1), HM_CLKCON);
205
206    /* CheckInternalClockStable */
207    for (i = 0; i < 0x10000; i++) {
208        reg16 = s3c_hsmmc_readw(HM_CLKCON);
209        if (reg16 & 0x2)
210            break;
211    }
212    if (i == 0x10000)
213        puts("internal clock stabilization failed\n");
214
215    hsmmc_clock_onoff(1);
216}
217
218static void set_cmd_register (ushort cmd, u32 data, u32 flags)
219{
220    ushort val = (cmd << 8);
221
222    if (cmd == 12)
223        val |= (3 << 6);
224
225    if (flags & MMC_RSP_136) /* Long RSP */
226        val |= 0x01;
227    else if (flags & MMC_RSP_BUSY) /* R1B */
228        val |= 0x03;
229    else if (flags & MMC_RSP_PRESENT) /* Normal RSP */
230        val |= 0x02;
231
232    if (flags & MMC_RSP_OPCODE)
233        val |= (1<<4);
234
235    if (flags & MMC_RSP_CRC)
236        val |= (1<<3);
237
238    if (data)
239        val |= (1<<5);
240
241// puts("cmdreg = 0x");
242// print32(val);
243// puts("\n");
244    s3c_hsmmc_writew(val, HM_CMDREG);
245}
246
247static int issue_command (ushort cmd, u32 arg, u32 data, u32 flags)
248{
249    int i;
250
251/* puts("### issue_command: ");
252    printdec(cmd);
253    puts(" 0x");
254    print32(arg);
255    puts(" ");
256    printdec(data);
257    puts(" 0x");
258    print32(flags);
259    puts("\n");
260*/
261    /* Check CommandInhibit_CMD */
262    for (i = 0; i < 0x1000000; i++) {
263        if (!(s3c_hsmmc_readl(HM_PRNSTS) & 0x1))
264            break;
265    }
266    if (i == 0x1000000) {
267        puts("@@@@@@1 rHM_PRNSTS: ");
268        printdec(s3c_hsmmc_readl(HM_PRNSTS));
269        puts("\n");
270    }
271
272    /* Check CommandInhibit_DAT */
273    if (flags & MMC_RSP_BUSY) {
274        for (i = 0; i < 0x1000000; i++) {
275            if (!(s3c_hsmmc_readl(HM_PRNSTS) & 0x2))
276                break;
277        }
278        if (i == 0x1000000) {
279            puts("@@@@@@2 rHM_PRNSTS: ");
280            print32(s3c_hsmmc_readl(HM_PRNSTS));
281            puts("\n");
282        }
283    }
284
285    s3c_hsmmc_writel(arg, HM_ARGUMENT);
286
287    set_cmd_register(cmd, data, flags);
288
289    if (wait_for_cmd_done())
290        return 0;
291
292    ClearCommandCompleteStatus();
293
294    if (!(s3c_hsmmc_readw(HM_NORINTSTS) & 0x8000))
295        return 1;
296
297    puts("Command = ");
298    printdec((s3c_hsmmc_readw(HM_CMDREG) >> 8));
299    puts(", Error Stat = 0x");
300    print32(s3c_hsmmc_readw(HM_ERRINTSTS));
301    return 0;
302}
303
304static int check_card_status(void)
305{
306    if (!issue_command(MMC_SEND_STATUS, rca<<16, 0, MMC_RSP_R1))
307        return 0;
308
309    if (((s3c_hsmmc_readl(HM_RSPREG0) >> 9) & 0xf) == 4) {
310// puts("Card is transfer status\n");
311        return 1;
312    }
313
314    return 1;
315}
316
317static void set_hostctl_speed (u8 mode)
318{
319    u8 reg8;
320
321    reg8 = s3c_hsmmc_readb(HM_HOSTCTL) & ~(0x1<<2);
322    s3c_hsmmc_writeb(reg8 | (mode<<2), HM_HOSTCTL);
323}
324
325/* return 0: OK
326 * return -1: error
327 */
328static int set_bus_width (u32 width)
329{
330    u8 reg = s3c_hsmmc_readb(HM_HOSTCTL);
331    u8 bitmode = 0;
332
333    card_irq_enable(0); // Disable sd card interrupt
334
335
336    if (!issue_command(MMC_APP_CMD, rca<<16, 0, MMC_RSP_R1))
337        return -1;
338    else {
339        if (width == 1) { // 1-bits
340            bitmode = 0;
341            if (!issue_command(MMC_SWITCH, 0, 0, MMC_RSP_R1B))
342                return -1;
343        } else { // 4-bits
344            bitmode = 1;
345            if (!issue_command(MMC_SWITCH, 2, 0, MMC_RSP_R1B))
346                return -1;
347        }
348    }
349
350    if (bitmode == 2)
351        reg |= 1 << 5;
352    else
353        reg |= bitmode << 1;
354
355    s3c_hsmmc_writeb(reg, HM_HOSTCTL);
356    card_irq_enable(1);
357// puts(" transfer rHM_HOSTCTL(0x28) = 0x");
358// print32(s3c_hsmmc_readb(HM_HOSTCTL));
359
360    return 0;
361}
362
363static void clock_config (u32 Divisior)
364{
365    if (100000000 / (Divisior * 2) > 25000000) // Higher than 25MHz, it is necessary to enable high speed mode of the host controller.
366        set_hostctl_speed(HIGH);
367    else
368        set_hostctl_speed(NORMAL);
369
370    hsmmc_clock_onoff(0); // when change the sd clock frequency, need to stop sd clock.
371    set_clock(SD_EPLL, Divisior);
372}
373
374static void check_dma_int (void)
375{
376    u32 i;
377
378    for (i = 0; i < 0x10000000; i++) {
379        if (s3c_hsmmc_readw(HM_NORINTSTS) & 0x0002) {
380            HS_DMA_END = 1;
381            s3c_hsmmc_writew(s3c_hsmmc_readw(HM_NORINTSTS) | 0x0002, HM_NORINTSTS);
382            return;
383        }
384        if (s3c_hsmmc_readw(HM_NORINTSTS) & 0x8000) {
385            puts("error found: ");
386            print32(s3c_hsmmc_readw(HM_ERRINTSTS));
387            return;
388        }
389    }
390
391    puts("check_dma_int: timeout\n");
392}
393
394
395static void print_sd_cid(const struct sd_cid *cid)
396{
397    puts(" Card Type: ");
398    switch (card_type) {
399    case CARDTYPE_NONE:
400        puts("(None) / ");
401        break;
402    case CARDTYPE_MMC:
403        puts("MMC / ");
404        break;
405    case CARDTYPE_SD:
406        puts("SD / ");
407        break;
408    case CARDTYPE_SD20:
409        puts("SD 2.0 / ");
410        break;
411    case CARDTYPE_SDHC:
412        puts("SD 2.0 SDHC / ");
413        break;
414    }
415
416    puts("Mfr: 0x");
417    print8(cid->mid);
418    puts(", OEM \"");
419    this_board->putc(cid->oid_0);
420    this_board->putc(cid->oid_1);
421    puts("\" / ");
422
423    this_board->putc(cid->pnm_0);
424    this_board->putc(cid->pnm_1);
425    this_board->putc(cid->pnm_2);
426    this_board->putc(cid->pnm_3);
427    this_board->putc(cid->pnm_4);
428    puts("\", rev ");
429    printdec(cid->prv >> 4);
430    puts(".");
431    printdec(cid->prv & 15);
432    puts(" / s/n: ");
433    print32(cid->psn_0 << 24 | cid->psn_1 << 16 | cid->psn_2 << 8 |
434        cid->psn_3);
435    puts(" / date: ");
436    printdec(cid->mdt_1 & 15);
437    puts("/");
438    printdec(2000 + ((cid->mdt_0 & 15) << 4)+((cid->mdt_1 & 0xf0) >> 4));
439    puts("\n");
440}
441
442unsigned int s3c6410_mmc_init (int verbose)
443{
444    u32 reg;
445    u32 width;
446    int resp;
447    int hcs;
448    int retries = 50;
449    u8 response[16];
450    unsigned int r1[4];
451    struct sd_cid *sd_cid = (struct sd_cid *)response;
452    struct mmc_csd *csd = (struct mmc_csd *)response;
453    u8 *p8 = (u8 *)&r1[0];
454    unsigned int sd_sectors = 0;
455    /* we need to shift result by 8 bits spread over 4 x 32-bit regs */
456    u8 mangle[] = { 7, 0, 1, 2, 11, 4, 5, 6, 15, 8, 9, 10, 0, 12, 13, 14 };
457    int n;
458
459    hsmmc_set_gpio();
460
461    hsmmc_reset();
462
463    width = 4;
464
465    HCLK = 33000000; /* FIXME */
466    hsmmc_clock_onoff(0);
467
468    reg = readl(SCLK_GATE);
469    writel(reg | (1<<27), SCLK_GATE);
470
471    set_clock(SD_EPLL, 0x80);
472    s3c_hsmmc_writeb(0xe, HM_TIMEOUTCON);
473    set_hostctl_speed(NORMAL);
474
475    InterruptEnable(0xff, 0xff);
476
477// dbg("HM_NORINTSTS = %x\n", s3c_hsmmc_readw(HM_NORINTSTS));
478
479    /* MMC_GO_IDLE_STATE */
480    issue_command(MMC_GO_IDLE_STATE, 0x00, 0, 0);
481
482    udelay(100000);
483    udelay(100000);
484    udelay(100000);
485    udelay(100000);
486
487    /* SDHC card? */
488
489    resp = issue_command(SD_SEND_IF_COND, 0x000001aa,
490        0, MMC_CMD_BCR | MMC_RSP_R7);
491    if (resp && ((s3c_hsmmc_readl(HM_RSPREG0) & 0xff) == 0xaa)) {
492        card_type = CARDTYPE_SD20; /* 2.0 SD, may not be SDHC */
493        hcs = 0x40000000;
494    }
495
496    /* Well, either way let's say hello in SD card protocol */
497
498    while (retries--) {
499
500        udelay(100000);
501        udelay(100000);
502        udelay(100000);
503
504        resp = issue_command(MMC_APP_CMD, 0x00000000, 0,
505            MMC_RSP_R1);
506        if (!resp)
507            continue;
508        resp = issue_command(SD_APP_OP_COND, hcs | 0x00300000, 0,
509            MMC_RSP_R3);
510        if (!resp)
511            continue;
512
513        if ((s3c_hsmmc_readl(HM_RSPREG0) >> 24) & (1 << 6)) { /* asserts block addressing */
514            retries = -2;
515            card_type = CARDTYPE_SDHC;
516        }
517
518        if ((s3c_hsmmc_readl(HM_RSPREG0) >> 24) & (1 << 7)) { /* not busy */
519            retries = -2;
520            if (card_type == CARDTYPE_NONE)
521                card_type = CARDTYPE_SD;
522            break;
523        }
524    }
525    if (retries == -1) {
526        puts("no response\n");
527        return -2;
528    }
529
530    if (!issue_command(MMC_ALL_SEND_CID, 0, 0, MMC_RSP_R2)) {
531        puts("CID broken\n");
532        return -3;
533    }
534
535    r1[0] = s3c_hsmmc_readl(HM_RSPREG3);
536    r1[1] = s3c_hsmmc_readl(HM_RSPREG2);
537    r1[2] = s3c_hsmmc_readl(HM_RSPREG1);
538    r1[3] = s3c_hsmmc_readl(HM_RSPREG0);
539
540    for (n = 0; n < 16; n++)
541        response[n] = p8[mangle[n]];
542
543    switch (card_type) {
544    case CARDTYPE_SD:
545    case CARDTYPE_SD20:
546    case CARDTYPE_SDHC:
547
548        if (verbose)
549            print_sd_cid(sd_cid);
550        resp = issue_command(SD_SEND_RELATIVE_ADDR, MMC_DEFAULT_RCA,
551                0, MMC_RSP_R6);
552        rca = s3c_hsmmc_readl(HM_RSPREG0) >> 16;
553        break;
554
555    default:
556        return 1;
557    }
558
559    /* grab the CSD */
560
561    resp = issue_command(MMC_SEND_CSD, rca << 16, 0, MMC_RSP_R2);
562    if (resp) {
563
564        r1[0] = s3c_hsmmc_readl(HM_RSPREG3);
565        r1[1] = s3c_hsmmc_readl(HM_RSPREG2);
566        r1[2] = s3c_hsmmc_readl(HM_RSPREG1);
567        r1[3] = s3c_hsmmc_readl(HM_RSPREG0);
568        for (n = 0; n < 16; n++)
569            response[n] = p8[mangle[n]];
570
571        switch (card_type) {
572        case CARDTYPE_SDHC:
573            puts(" SDHC size: ");
574            sd_sectors = (UNSTUFF_BITS(((u32 *)&response[0]), 48, 22)
575                                    + 1) << 10;
576            break;
577        default:
578            puts(" MMC/SD size: ");
579            sd_sectors = ((((unsigned long)1 << csd->c_size_mult1) *
580                    (unsigned long)(csd->c_size)) >> 9);
581        }
582        printdec(sd_sectors / 2048);
583        puts(" MiB\n");
584    } else
585        puts("CSD grab broken\n");
586
587    resp = issue_command(MMC_SELECT_CARD, rca<<16, 0, MMC_RSP_R1);
588    if (!resp)
589        return 1;
590
591    /* Operating Clock setting */
592    clock_config(2); // Divisor 1 = Base clk /2 ,Divisor 2 = Base clk /4, Divisor 4 = Base clk /8 ...
593
594    while (set_bus_width(width));
595    while (!check_card_status());
596
597    /* MMC_SET_BLOCKLEN */
598    while (!issue_command(MMC_SET_BLOCKLEN, 512, 0, MMC_RSP_R1));
599
600    s3c_hsmmc_writew(0xffff, HM_NORINTSTS);
601
602    return sd_sectors;
603}
604
605unsigned long s3c6410_mmc_bread(int dev_num, unsigned long start_blk, unsigned long blknum,
606                                      void *dst)
607{
608    u32 blksize; //j, , Addr_temp = start_blk;
609    u32 dma = 0, cmd, multi; //, TotalReadByte, read_blk_cnt = 0;
610
611    HS_DMA_END = 0;
612
613    blksize = Card_OneBlockSize_ver1;
614
615    while (!check_card_status());
616
617    s3c_hsmmc_writew(s3c_hsmmc_readw(HM_NORINTSTSEN) & ~(DMA_STS_INT_EN | BLOCKGAP_EVENT_STS_INT_EN), HM_NORINTSTSEN);
618    s3c_hsmmc_writew((HM_NORINTSIGEN & ~(0xffff)) | TRANSFERCOMPLETE_SIG_INT_EN, HM_NORINTSIGEN);
619
620    SetSystemAddressReg((unsigned long)dst); // AHB System Address For Write
621    dma = 1;
622
623    set_blksize_register(7, 512); // Maximum DMA Buffer Size, Block Size
624    set_blkcnt_register(blknum); // Block Numbers to Write
625
626    if (movi_hc)
627        set_arg_register(start_blk); // Card Start Block Address to Write
628    else
629        set_arg_register(start_blk * 512); // Card Start Block Address to Write
630
631    cmd = (blknum > 1) ? 18 : 17;
632    multi = (blknum > 1);
633
634    set_transfer_mode_register(multi, 1, multi, 1, dma);
635    set_cmd_register(cmd, 1, MMC_RSP_R1);
636
637    if (wait_for_cmd_done()) {
638        puts("Command NOT Complete\n");
639        return -1;
640    } else
641        ClearCommandCompleteStatus();
642
643
644    check_dma_int();
645    while (!HS_DMA_END);
646
647    HS_DMA_END = 0;
648
649    return blknum;
650}
651

Archive Download this file



interactive