1/**
2 * \file
3 * \brief OMAP44xx MMC Controller driver implementation
4 */
5/*
6 * Copyright (c) 2013, ETH Zurich.
7 * All rights reserved.
8 *
9 * This file is distributed under the terms in the attached LICENSE file.
10 * If you do not find this file, copies can be found by writing to:
11 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
12 */
13
14#include <barrelfish/barrelfish.h>
15#include <barrelfish/inthandler.h>
16
17#include <maps/omap44xx_map.h>
18
19#include <driverkit/driverkit.h>
20#include <arch/arm/omap44xx/device_registers.h>
21#include <if/cm2_defs.h>
22
23#include "mmchs.h"
24#include "cap_slots.h"
25
26static void mmchs_soft_reset(struct mmchs_driver_state* st)
27{
28    MMCHS_DEBUG("%s:%d\n", __FUNCTION__, __LINE__);
29    omap44xx_mmchs1_mmchs_sysconfig_softreset_wrf(&st->mmchs, 0x1);
30    while (omap44xx_mmchs1_mmchs_sysstatus_resetdone_rdf(&st->mmchs) != 0x1);
31
32    MMCHS_DEBUG("%s:%d: sysctl reset\n", __FUNCTION__, __LINE__);
33    omap44xx_mmchs1_mmchs_sysctl_sra_wrf(&st->mmchs, 0x1);
34    while (omap44xx_mmchs1_mmchs_sysctl_sra_rdf(&st->mmchs) != 0x0);
35}
36
37static void set_hardware_capabilities(struct mmchs_driver_state* st)
38{
39    omap44xx_mmchs1_mmchs_capa_vs18_wrf(&st->mmchs, 0x1);
40    omap44xx_mmchs1_mmchs_capa_vs30_wrf(&st->mmchs, 0x1);
41}
42
43static void set_wake_up_configuration(struct mmchs_driver_state* st)
44{
45    omap44xx_mmchs1_mmchs_sysconfig_enawakeup_wrf(&st->mmchs, 0x1);
46    omap44xx_mmchs1_mmchs_hctl_iwe_wrf(&st->mmchs, 0x1);
47}
48
49/**
50 * \see TRM rev Z, Section 24.5.1.2.1.7.2
51 */
52static void change_clock_frequency_to_fit_protocol(struct mmchs_driver_state* st, uint32_t clock)
53{
54    omap44xx_mmchs1_mmchs_sysctl_cen_wrf(&st->mmchs, 0x0);
55    omap44xx_mmchs1_mmchs_sysctl_clkd_wrf(&st->mmchs, clock);
56
57    MMCHS_DEBUG("%s:%d: Wait until clock is stable.\n", __FUNCTION__, __LINE__);
58    while (omap44xx_mmchs1_mmchs_sysctl_ics_rdf(&st->mmchs) != 0x1);
59
60    omap44xx_mmchs1_mmchs_sysctl_cen_wrf(&st->mmchs, 0x1);
61}
62
63static void mmc_host_and_bus_configuration(struct mmchs_driver_state* st)
64{
65    omap44xx_mmchs1_mmchs_con_od_wrf(&st->mmchs, 0x0);
66    omap44xx_mmchs1_mmchs_con_dw8_wrf(&st->mmchs, 0x0);
67    omap44xx_mmchs1_mmchs_con_ceata_wrf(&st->mmchs, 0x0);
68
69    omap44xx_mmchs1_mmchs_hctl_sdvs_wrf(&st->mmchs, 0x6);
70    omap44xx_mmchs1_mmchs_hctl_sdbp_wrf(&st->mmchs, 0x0);
71    omap44xx_mmchs1_mmchs_hctl_dtw_wrf(&st->mmchs, 0x0);
72
73    omap44xx_mmchs1_mmchs_sysctl_cen_wrf(&st->mmchs, 0x0);
74    omap44xx_mmchs1_mmchs_sysctl_ice_wrf(&st->mmchs, 0x1);
75
76    uint32_t clock = 0;
77    st->cm2_binding->rpc_tx_vtbl.get_hsmmc1_base_clock(st->cm2_binding, &clock);
78    MMCHS_DEBUG("%s:%d: clksel = %u\n", __FUNCTION__, __LINE__, clock);
79    change_clock_frequency_to_fit_protocol(st, 0x258);
80
81    MMCHS_DEBUG("%s:%d: Wait until internal clock is stable.\n", __FUNCTION__, __LINE__);
82    while (omap44xx_mmchs1_mmchs_sysctl_ics_rdf(&st->mmchs) != 0x1);
83
84    omap44xx_mmchs1_mmchs_hctl_sdbp_wrf(&st->mmchs, 0x1);
85    assert(omap44xx_mmchs1_mmchs_hctl_sdbp_rdf(&st->mmchs) == 0x1);
86
87    // Pessimistic settings, we want to have this thing always ON for testing
88    omap44xx_mmchs1_mmchs_sysconfig_clockactivity_wrf(&st->mmchs, 0x3);
89    omap44xx_mmchs1_mmchs_sysconfig_standbymode_wrf(&st->mmchs, 0x1);
90    omap44xx_mmchs1_mmchs_sysconfig_sidlemode_wrf(&st->mmchs, 0x1);
91    omap44xx_mmchs1_mmchs_sysconfig_autoidle_wrf(&st->mmchs, 0x0);
92}
93
94/**
95 * \see TRM rev Z, Section 24.5.1.2.1.1.1
96 */
97static void cmd_line_reset(struct mmchs_driver_state* st)
98{
99    MMCHS_DEBUG("%s:%d\n", __FUNCTION__, __LINE__);
100
101    omap44xx_mmchs1_mmchs_sysctl_src_wrf(&st->mmchs, 0x1);
102    while (omap44xx_mmchs1_mmchs_sysctl_src_rdf(&st->mmchs) != 0x1);
103    while (omap44xx_mmchs1_mmchs_sysctl_src_rdf(&st->mmchs) != 0x0);
104}
105
106/**
107 * \see TRM rev Z, Section 24.5.1.2.1.2.1
108 */
109static void dat_line_reset(struct mmchs_driver_state* st)
110{
111    MMCHS_DEBUG("%s:%d\n", __FUNCTION__, __LINE__);
112
113    omap44xx_mmchs1_mmchs_sysctl_srd_wrf(&st->mmchs, 0x1);
114    while (omap44xx_mmchs1_mmchs_sysctl_srd_rdf(&st->mmchs) != 0x1);
115    while (omap44xx_mmchs1_mmchs_sysctl_srd_rdf(&st->mmchs) != 0x0);
116}
117
118
119// TODO(gz): Got this from old mmchs code, its ugly and should
120// go away with a proper sleep functionality
121volatile uint32_t dummy = 0;
122static void wait_msec(long msec)
123{
124    int i = 0, sum = 0;
125    long end = (1200000 * msec / 8);
126
127    // Cannot use volatile variables in loop
128    while (++i < end)  {
129        sum += i + end;
130    }
131
132    dummy += sum;
133}
134
135
136/**
137 * \see TRM rev Z, Section 24.5.1.2.1.7.1
138 */
139static void send_command(struct mmchs_driver_state* st, omap44xx_mmchs1_indx_status_t cmd, uint32_t arg)
140{
141    MMCHS_DEBUG("%s:%d: cmd = 0x%x arg=0x%x\n", __FUNCTION__, __LINE__, cmd, arg);
142
143    MMCHS_DEBUG("%s:%d: Wait until command line is free.\n", __FUNCTION__, __LINE__);
144    while (omap44xx_mmchs1_mmchs_pstate_cmdi_rdf(&st->mmchs) != 0x0);
145    MMCHS_DEBUG("%s:%d: \n", __FUNCTION__, __LINE__);
146
147    omap44xx_mmchs1_mmchs_stat_rawwr(&st->mmchs, ~0x0);
148
149    // Only for MMC cards
150    omap44xx_mmchs1_mmchs_con_mit_wrf(&st->mmchs, 0x0);
151    omap44xx_mmchs1_mmchs_con_str_wrf(&st->mmchs, 0x0);
152
153    omap44xx_mmchs1_mmchs_csre_rawwr(&st->mmchs, 0x0);
154
155    omap44xx_mmchs1_mmchs_blk_blen_wrf(&st->mmchs, 512);
156    omap44xx_mmchs1_mmchs_blk_nblk_wrf(&st->mmchs, 0x1);
157
158    omap44xx_mmchs1_mmchs_sysctl_dto_wrf(&st->mmchs, 0xE); // omapconf
159
160    omap44xx_mmchs1_mmchs_arg_rawwr(&st->mmchs, arg);
161
162    // Enable interrupts
163    omap44xx_mmchs1_mmchs_ie_rawwr(&st->mmchs, ~0x0);
164    //omap44xx_mmchs1_mmchs_ise_rawwr(&st->mmchs, ~0x0);
165
166    omap44xx_mmchs1_mmchs_cmd_t cmdreg = omap44xx_mmchs1_mmchs_cmd_default;
167
168    // see TRM rev Z, Table 24-4
169    // and Physical Layer Simplified Spec 3.01, Section 4.7.4
170    switch (cmd) {
171        // R2
172    case omap44xx_mmchs1_INDX_2:
173    case omap44xx_mmchs1_INDX_9:
174        cmdreg = omap44xx_mmchs1_mmchs_cmd_rsp_type_insert(cmdreg, 0x1);
175        cmdreg = omap44xx_mmchs1_mmchs_cmd_ccce_insert(cmdreg, 0x1);
176        break;
177        // R1, R6, R5, R7
178    case omap44xx_mmchs1_INDX_17:
179        cmdreg = omap44xx_mmchs1_mmchs_cmd_ddir_insert(cmdreg, 0x1);
180    case omap44xx_mmchs1_INDX_24:
181        cmdreg = omap44xx_mmchs1_mmchs_cmd_dp_insert(cmdreg, 0x1);
182        cmdreg = omap44xx_mmchs1_mmchs_cmd_acen_insert(cmdreg, 0x1);
183        // Fallthrough desired!
184    case omap44xx_mmchs1_INDX_0:
185    case omap44xx_mmchs1_INDX_3:
186    case omap44xx_mmchs1_INDX_5:
187    case omap44xx_mmchs1_INDX_8:
188    case omap44xx_mmchs1_INDX_16:
189    case omap44xx_mmchs1_INDX_41:
190    case omap44xx_mmchs1_INDX_55:
191        cmdreg = omap44xx_mmchs1_mmchs_cmd_rsp_type_insert(cmdreg, 0x2);
192        cmdreg = omap44xx_mmchs1_mmchs_cmd_ccce_insert(cmdreg, 0x1);
193        cmdreg = omap44xx_mmchs1_mmchs_cmd_cice_insert(cmdreg, 0x1);
194        break;
195        // R1b, R5b
196    case omap44xx_mmchs1_INDX_7:
197    case omap44xx_mmchs1_INDX_12:
198        cmdreg = omap44xx_mmchs1_mmchs_cmd_rsp_type_insert(cmdreg, 0x3);
199        cmdreg = omap44xx_mmchs1_mmchs_cmd_ccce_insert(cmdreg, 0x1);
200        cmdreg = omap44xx_mmchs1_mmchs_cmd_cice_insert(cmdreg, 0x1);
201        break;
202    default:
203        assert(!"Unsupported command\n");
204        break;
205    }
206
207    cmdreg = omap44xx_mmchs1_mmchs_cmd_indx_insert(cmdreg, cmd);
208    omap44xx_mmchs1_mmchs_cmd_wr(&st->mmchs, cmdreg);
209
210    MMCHS_DEBUG("%s:%d: Wait until mmchs_stat.cc == 0x1\n", __FUNCTION__, __LINE__);
211    uint32_t cc = 0;
212    size_t i = 0;
213    do {
214        uint32_t cto = omap44xx_mmchs1_mmchs_stat_cto_rdf(&st->mmchs);
215        uint32_t ccrc = omap44xx_mmchs1_mmchs_stat_ccrc_rdf(&st->mmchs);
216        cc = omap44xx_mmchs1_mmchs_stat_cc_rdf(&st->mmchs);
217
218        if (cto == 0x1 && ccrc == 0x1) {
219            MMCHS_DEBUG("%s:%d: cto = 1 ccrc = 1: Conflict on cmd line.\n", __FUNCTION__, __LINE__);
220            cmd_line_reset(st);
221            return;
222        }
223        if (cto == 0x1 && ccrc == 0x0) {
224            MMCHS_DEBUG("%s:%d: cto = 1 ccrc = 0: Abort.\n", __FUNCTION__, __LINE__);
225            cmd_line_reset(st);
226            return;
227        }
228
229        if (i++ > 1000) {
230            omap44xx_mmchs1_mmchs_stat_pr(st->dbuf, DBUF_SIZE, &st->mmchs);
231            MMCHS_DEBUG("%s:%d: %s\n", __FUNCTION__, __LINE__, st->dbuf);
232            USER_PANIC("Command not Ackd?");
233        }
234        wait_msec(1);
235    } while (cc != 0x1);
236
237
238    /*omap44xx_mmchs1_mmchs_pstate_pr(dbuf, DBUF_SIZE, &mmchs);
239    MMCHS_DEBUG("%s:%d: \n%s\n", __FUNCTION__, __LINE__, st->dbuf);
240    MMCHS_DEBUG("%s:%d: mmchs_rsp10 = 0x%x\n", __FUNCTION__, __LINE__,
241           omap44xx_mmchs1_mmchs_rsp10_rd(&st->mmchs));
242    MMCHS_DEBUG("%s:%d: mmchs_rsp32 = 0x%x\n", __FUNCTION__, __LINE__,
243           omap44xx_mmchs1_mmchs_rsp32_rd(&st->mmchs));
244    MMCHS_DEBUG("%s:%d: mmchs_rsp54 = 0x%x\n", __FUNCTION__, __LINE__,
245           omap44xx_mmchs1_mmchs_rsp54_rd(&st->mmchs));
246    MMCHS_DEBUG("%s:%d: mmchs_rsp76 = 0x%x\n", __FUNCTION__, __LINE__,
247           omap44xx_mmchs1_mmchs_rsp76_rd(&st->mmchs));*/
248
249
250    uint32_t resp_type = omap44xx_mmchs1_mmchs_cmd_rsp_type_rdf(&st->mmchs);
251    if (resp_type == 0x0) {
252        MMCHS_DEBUG("%s:%d: No response.\n", __FUNCTION__, __LINE__);
253        return;
254    }
255}
256
257
258/**
259 * \see TRM rev Z, Figure 24-38
260 */
261static void mmchs_identify_card(struct mmchs_driver_state* st)
262{
263    // Module Initialization is done in mmchs_init()
264    omap44xx_mmchs1_mmchs_ie_rawwr(&st->mmchs, 0xFFFFFFFF);
265
266    omap44xx_mmchs1_mmchs_con_init_wrf(&st->mmchs, 0x1);
267
268    omap44xx_mmchs1_mmchs_cmd_rawwr(&st->mmchs, 0x0);
269    while (omap44xx_mmchs1_mmchs_stat_cc_rdf(&st->mmchs) != 0x1);
270
271    wait_msec(10);
272    omap44xx_mmchs1_mmchs_stat_cc_wrf(&st->mmchs, 0x1);
273
274    omap44xx_mmchs1_mmchs_cmd_rawwr(&st->mmchs, 0x0);
275    while (omap44xx_mmchs1_mmchs_stat_cc_rdf(&st->mmchs) != 0x1);
276
277    omap44xx_mmchs1_mmchs_stat_cc_wrf(&st->mmchs, 0x1);
278    omap44xx_mmchs1_mmchs_con_init_wrf(&st->mmchs, 0x0);
279
280    //omap44xx_mmchs1_mmchs_stat_rawwr(&st->mmchs, 0xFFFFFFFF);
281
282    omap44xx_mmchs1_mmchs_hctl_sdbp_wrf(&st->mmchs, 0x1);
283    change_clock_frequency_to_fit_protocol(st, 0xF0UL);
284
285    send_command(st, 0, 0x0);
286
287    uint32_t arg8 = (0x1  << 8) | 0b10101010;
288    send_command(st, 8, arg8);
289    assert(omap44xx_mmchs1_mmchs_stat_cc_rdf(&st->mmchs) == 0x1);
290
291    send_command(st, 55, 0x0);
292    uint32_t ocrdata = 0;
293    do {
294        send_command(st, 55, 0x0);
295        MMCHS_DEBUG("%s:%d: ACMD41\n", __FUNCTION__, __LINE__);
296        uint32_t arg41 = 0x1 << 30 | ocrdata;
297        send_command(st, 41, arg41);
298        wait_msec(10);
299        ocrdata = omap44xx_mmchs1_mmchs_rsp10_rd(&st->mmchs);
300    } while ((omap44xx_mmchs1_mmchs_rsp10_rd(&st->mmchs) & (1 << 31)) == 0);
301
302    MMCHS_DEBUG("%s:%d: CMD2\n", __FUNCTION__, __LINE__);
303    send_command(st, 2, 0x0);
304
305    MMCHS_DEBUG("%s:%d: CMD3\n", __FUNCTION__, __LINE__);
306    send_command(st, 3, 0x1);
307    uint32_t rca = omap44xx_mmchs1_mmchs_rsp10_rd(&st->mmchs) >> 16;
308    MMCHS_DEBUG("Status: 0x%X\n", rca & 0xFFFF);
309    MMCHS_DEBUG("RCA: 0x%X\n", (rca >> 16) & 0xFFFF);
310
311    MMCHS_DEBUG("%s:%d: CMD9\n", __FUNCTION__, __LINE__);
312    send_command(st, 9, rca << 16);
313
314    MMCHS_DEBUG("%s:%d: CMD7\n", __FUNCTION__, __LINE__);
315    send_command(st, 7, rca << 16);
316
317    MMCHS_DEBUG("%s:%d: CMD16\n", __FUNCTION__, __LINE__);
318    send_command(st, 16, 512);
319}
320
321static errval_t complete_card_transaction(struct mmchs_driver_state* st)
322{
323    size_t i = 0;
324    do {
325        if ( omap44xx_mmchs1_mmchs_stat_tc_rdf(&st->mmchs) == 0x1 )  {
326            //send_command(12, 0);
327            return SYS_ERR_OK; // Fine as long as we support only finite transfers
328        } else {
329            bool deb = omap44xx_mmchs1_mmchs_stat_deb_rdf(&st->mmchs);
330            bool dcrc = omap44xx_mmchs1_mmchs_stat_dcrc_rdf(&st->mmchs);
331            bool dto = omap44xx_mmchs1_mmchs_stat_dto_rdf(&st->mmchs);
332
333            if (deb || dcrc || dto) {
334                MMCHS_DEBUG("%s:%d: Error interrupt during transfer: deb=%d dcrc=%d dto=%d.\n",
335                            __FUNCTION__, __LINE__, deb, dcrc, dto);
336                dat_line_reset(st);
337                return MMC_ERR_TRANSFER;
338            }
339        }
340
341        wait_msec(10);
342    } while (i++ < 1000);
343
344    MMCHS_DEBUG("%s:%d: No transfer complete interrupt?\n", __FUNCTION__, __LINE__);
345    return MMC_ERR_TRANSFER;
346}
347
348/**
349 * \brief Reads a 512-byte block on the card.
350 *
351 * \param block_nr Index number of block to read.
352 * \param buffer Non-null buffer with a size of at least 512 bytes.
353 *
354 * \retval SYS_ERR_OK Block successfully written in buffer.
355 * \retval MMC_ERR_TRANSFER Error interrupt or no transfer complete interrupt.
356 * \retval MMC_ERR_READ_READY Card not ready to read.
357 */
358errval_t mmchs_read_block(struct mmchs_driver_state* st, size_t block_nr, void *buffer)
359{
360    MMCHS_DEBUG("%s:%d: Wait for free data lines.\n", __FUNCTION__, __LINE__);
361    while (omap44xx_mmchs1_mmchs_pstate_dati_rdf(&st->mmchs) != 0x0);
362
363    // Send data command
364    send_command(st, 17, block_nr);
365    // TODO(gz): Check for errors
366
367    for (size_t i = 0; i < (omap44xx_mmchs1_mmchs_blk_blen_rdf(&st->mmchs) + 3) / 4; i++) {
368        size_t timeout = 1000;
369        while (omap44xx_mmchs1_mmchs_stat_brr_rdf(&st->mmchs) == 0x0 && timeout--) {
370            wait_msec(1);
371        }
372        if (timeout == 0) {
373            return MMC_ERR_READ_READY;
374        }
375
376        ((uint32_t *) buffer)[i] = omap44xx_mmchs1_mmchs_data_rd(&st->mmchs);
377    }
378
379    return complete_card_transaction(st);
380}
381
382/**
383 * \brief Write a 512-byte block in the card.
384 *
385 * \param block_nr Index number of block to write.
386 * \param buffer Data to write (must be at least 512 bytes in size).
387 *
388 * \retval SYS_ERR_OK Block written to card.
389 * \retval MMC_ERR_TRANSFER Error interrupt or no transfer complete interrupt.
390 * \retval MMC_ERR_WRITE_READY Card not ready to write.
391 */
392errval_t mmchs_write_block(struct mmchs_driver_state* st, size_t block_nr, void *buffer)
393{
394    MMCHS_DEBUG("%s:%d: Wait for free data lines.\n", __FUNCTION__, __LINE__);
395    size_t timeout = 1000;
396    while (omap44xx_mmchs1_mmchs_pstate_dati_rdf(&st->mmchs) != 0x0 && timeout--) {
397        wait_msec(1);
398    }
399    if (timeout == 0) {
400        return MMC_ERR_WRITE_READY;
401    }
402
403    // Send data command
404    send_command(st, 24, block_nr);
405    // TODO(gz): Check for errors
406
407    for (size_t i = 0; i < (omap44xx_mmchs1_mmchs_blk_blen_rdf(&st->mmchs) + 3) / 4; i++) {
408        while (omap44xx_mmchs1_mmchs_stat_bwr_rdf(&st->mmchs) == 0x0);
409        omap44xx_mmchs1_mmchs_data_wr(&st->mmchs, ((uint32_t *) buffer)[i]);
410    }
411
412    return complete_card_transaction(st);
413}
414
415/**
416 * MMC Initialization
417 *
418 * \see TRM rev Z, 24.5.1.1.2
419 */
420void mmchs_init(struct mmchs_driver_state* st)
421{
422    lvaddr_t mmchs_vaddr;
423    errval_t err = map_device_cap(st->caps[L4_PER_HSMMC1_SLOT], &mmchs_vaddr);
424    assert(err_is_ok(err));
425
426    omap44xx_mmchs1_initialize(&st->mmchs, (mackerel_addr_t)mmchs_vaddr);
427
428    mmchs_soft_reset(st);
429    set_hardware_capabilities(st);
430    set_wake_up_configuration(st);
431    mmc_host_and_bus_configuration(st);
432
433    mmchs_identify_card(st);
434}
435