summaryrefslogtreecommitdiffstats
path: root/firmware/target/mips/ingenic_x1000/msc-x1000.h
blob: b7b05b859db0386118c320ff98830f3988caaccc (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
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2021 Aidan MacDonald
 *
 * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/

#ifndef __MSC_X1000_H__
#define __MSC_X1000_H__

#include "kernel.h"
#include "sdmmc.h"
#include <stdbool.h>

/* Number of MSC controllers */
#define MSC_COUNT 2

/* Media types */
#define MSC_TYPE_SD  0
#define MSC_TYPE_MMC 1
#define MSC_TYPE_ATA 2
#define MSC_TYPE_ANY 3

/* Clock modes */
#define MSC_CLK_MANUAL    0
#define MSC_CLK_AUTOMATIC 1

/* Clock status bits */
#define MSC_CLKST_ENABLE (1 << 0)
#define MSC_CLKST_AUTO   (1 << 1)

/* Driver flags */
#define MSC_DF_ERRSTATE (1 << 0)
#define MSC_DF_READY    (1 << 1)
#define MSC_DF_HCS_CARD (1 << 2)
#define MSC_DF_V2_CARD  (1 << 3)

/* Request status codes */
#define MSC_REQ_SUCCESS     0
#define MSC_REQ_CRC_ERR     1
#define MSC_REQ_CARD_ERR    2
#define MSC_REQ_TIMEOUT     3
#define MSC_REQ_EXTRACTED   4
#define MSC_REQ_LOCKUP      5
#define MSC_REQ_ERROR       6
#define MSC_REQ_INCOMPLETE  (-1)

/* Response types */
#define MSC_RESP_NONE   0
#define MSC_RESP_BUSY   (1 << 7)
#define MSC_RESP_R1     1
#define MSC_RESP_R1B    (MSC_RESP_R1|MSC_RESP_BUSY)
#define MSC_RESP_R2     2
#define MSC_RESP_R3     3
#define MSC_RESP_R6     6
#define MSC_RESP_R7     7

/* Request flags */
#define MSC_RF_INIT         (1 << 0)
#define MSC_RF_ERR_CMD12    (1 << 1)
#define MSC_RF_AUTO_CMD12   (1 << 2)
#define MSC_RF_PROG         (1 << 3)
#define MSC_RF_DATA         (1 << 4)
#define MSC_RF_WRITE        (1 << 5)
#define MSC_RF_ABORT        (1 << 6)

/* Clock speeds */
#define MSC_SPEED_INIT  400000
#define MSC_SPEED_FAST  25000000
#define MSC_SPEED_HIGH  50000000

typedef struct msc_config {
    int msc_nr;
    int msc_type;
    int bus_width;
    const char* label;
    int cd_gpio;
    int cd_active_level;
} msc_config;

typedef struct msc_req {
    /* Filled by caller */
    int command;
    unsigned argument;
    int resptype;
    int flags;
    void* data;
    unsigned nr_blocks;
    unsigned block_len;

    /* Filled by driver */
    volatile unsigned response[4];
    volatile int status;
} msc_req;

struct sd_dma_desc {
    unsigned nda;
    unsigned mem;
    unsigned len;
    unsigned cmd;
} __attribute__((aligned(16)));

typedef struct msc_drv {
    int msc_nr;
    int drive_nr;
    const msc_config* config;

    int driver_flags;
    int clk_status;
    unsigned cmdat_def;
    msc_req* req;
    unsigned iflag_done;

    volatile int req_running;
    volatile int card_present; /* Debounced status */
    volatile int card_present_last; /* Status when we last polled it */

    struct mutex lock;
    struct semaphore cmd_done;
    struct timeout cmd_tmo;
    struct timeout cd_tmo;
    struct sd_dma_desc dma_desc;

    tCardInfo cardinfo;
} msc_drv;

/* Driver initialization, etc */
extern void msc_init(void);
extern msc_drv* msc_get(int type, int index);
extern msc_drv* msc_get_by_drive(int drive_nr);

extern void msc_lock(msc_drv* d);
extern void msc_unlock(msc_drv* d);
extern void msc_full_reset(msc_drv* d);
extern bool msc_card_detect(msc_drv* d);

/* Controller API */
extern void msc_ctl_reset(msc_drv* d);
extern void msc_set_clock_mode(msc_drv* d, int mode);
extern void msc_enable_clock(msc_drv* d, bool enable);
extern void msc_set_speed(msc_drv* d, int rate);
extern void msc_set_width(msc_drv* d, int width);

/* Request API */
extern void msc_async_start(msc_drv* d, msc_req* r);
extern void msc_async_abort(msc_drv* d, int status);
extern int  msc_async_wait(msc_drv* d, int timeout);
extern int  msc_request(msc_drv* d, msc_req* r);

/* Command helpers; note these are written with SD in mind
 * and should be reviewed before using them for MMC / CE-ATA
 */
extern int msc_cmd_exec(msc_drv* d, msc_req* r);
extern int msc_app_cmd_exec(msc_drv* d, msc_req* r);
extern int msc_cmd_go_idle_state(msc_drv* d);
extern int msc_cmd_send_if_cond(msc_drv* d);
extern int msc_cmd_app_op_cond(msc_drv* d);
extern int msc_cmd_all_send_cid(msc_drv* d);
extern int msc_cmd_send_rca(msc_drv* d);
extern int msc_cmd_send_csd(msc_drv* d);
extern int msc_cmd_select_card(msc_drv* d);
extern int msc_cmd_set_bus_width(msc_drv* d, int width);
extern int msc_cmd_set_clr_card_detect(msc_drv* d, int arg);
extern int msc_cmd_switch_freq(msc_drv* d);
extern int msc_cmd_send_status(msc_drv* d);
extern int msc_cmd_set_block_len(msc_drv* d, unsigned len);

#endif /* __MSC_X1000_H__ */