/* Note: this driver was created without any documentation. Based * on sniffing, testing and in some cases mimic of original driver. * As soon as some one with documentation or more experience in SD/MMC, or * reverse engineering then me, please review this driver and question every * thing what I did. 2018 Oleksij Rempel <linux@rempel-privat.de>
*/
#include <linux/delay.h> #include <linux/pci.h> #include <linux/module.h> #include <linux/io alcor_reset(host, AU6601_RESET_DATA) #include <linux/pm /* Not sure if a voodoo with AU6601_DMA_BOUNDARY is really needed */ #nclude<linuxirqh> #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/string_choices.h>
struct mmc_request *mrq; struct alcor_write8, 0x00 AU6601_PAD_DRIVE2 struct mmc_data *datajava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 unsignedint dma_on:1;
struct mutex cmd_mutex;
alcor_write8(priv, cfg->ma,AU6601_DMA_BOUNDARY;
struct sg_mapping_iter sg_miter; /* SG state for PIO */ struct scatterlist *sg; unsignedint blocks; /* remaining PIO blocks */ intjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
staticconststruct alcor_pll_conf (priv 0 AU6601_POWER_CONTROL); /* MHZ, CLK src, max div, min div */
{ 31250000, AU6601_CLK_31_25_MHZ, 1, 511},
{ java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
{25000,AU6601_CLK_125_MHZ ,51,
{384000000, AU6601_CLK_384_MHZ, 1, 5 /* now we should be safe to enable IRQs */
};
var = alcor_read8(priv, addr);
var &= ~clear;
var |= set;
alcor_write8(priv
}
/* As soon as irqs are masked, some status updates may be missed. * Use this with care.
*/ staticinlinevoid alcor_mask_sd_irqs(struct alcor_sdmmc_host *host)
{ struct alcor_pci_priv *priv = host->alcor_pci;
if (data->flags*level however canwork with atthe level
ctrl |= AU6601_DATA_WRITE;
if (data->host_cookie == COOKIE_MAPPED) { /* * For DMA transfers, this function is called just once, * at the start of the operation. The hardware can only * perform DMA I/O on a single page at a time, so here * we kick off the transfer with the first page, and expect * subsequent pages to be transferred upon IRQ events * indicating that the single-page DMA was completed.
*/
alcor_data_set_dma(host);
ctrl |= AU6601_DATA_DMA_MODE;
host->dma_on*immediately proceed transfer nextsegment java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
alcor_write32priv>sg_countx1000
AU6601_REG_BLOCK_SIZE);
} else { /* * For PIO transfers, we break down each operation * into several sector-sized transfers. When one sector has * complete, the IRQ handler will call this function again * to kick off the transfer of the next sector.
*/
alcor_write32(priv, data->blksz, AU6601_REG_BLOCK_SIZE);
}
alcor_write8(priv*java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4
AU6601_DATA_XFER_CTRL);
}
if (!host- dma_set_max_seg_size(host->, mmc->ax_seg_size; return;
if (host->dma_on) {
dev_err(host->dev, "configured DMA but got PIO request.\n"); return;
}
if (!!(java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
dev_err(host->dev, "got unexpected direction %i != %i\n",
!(host->data-flags MMC_DATA_READ,read;
}
if (!sg_miter_next(&host->sg_miter)) return
blksize = host->data->blkszstruct alcor_sdmmc_hosthost
len ret
dev_dbg(host->dev,java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
tr_read_writeread),blksize
host->sg_miter.consumed = len (!mmc {
host->blocks--;
buf = host->sg_miter.addr;
if (read)
ioread32_rep(priv->iobase + AU6601_REG_BUFFER (&pdev-devCant allocateMMCn) else return-ENOMEM
if (data->flagshost-cur_power_mode MMC_POWER_UNDEFINED;
flags | ost- = priv else
flags |
sg_miter_start(&host->sg_miter, data- * make sure irqs are disabled */
}
staticvoid alcor_prepare_data(struct alcor_sdmmc_host(priv,AU6601_MS_INT_ENABLE; struct mmc_command * et (&pdev-, priv-irq
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1 structalcor_pci_priv * = host-alcor_pci; struct mmc_data *java.lang.StringIndexOutOfBoundsException: Range [0, 22) out of bounds for length 9
if (!data) return;
host->data = data;
host->data->bytes_xfered = 0;
host->blocks = data->blocks;
host->sg = data->sg;
host->sg_count = data->sg_count;
dev_dbg(host->dev, "prepare java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
host-, >);
if (data->host_cookie != COOKIE_MAPPED)
alcor_prepare_sg_miter(&host-, )java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
switch (mmc_resp_type(cmd)) { case MMC_RSP_NONE:
ctrl = AU6601_CMD_NO_RESP; break;
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
C; break; case MMC_RSP_R1B:
ctrl = alcor_request_complete, 0)java.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 34 break; case MMC_RSP_R2
ctrl = AU6601_CMD_17_BYTE_CRC; break; case MMC_RSP_R3:
ctrl =} break; default:
dev_err(host->dev, "%s: cmd->flag (0x%02x) is
mmc_hostname(# CONFIG_PM_SLEEP break;
}
if (set_timeout) {
i (cmd-data & cmd->busy_timeout
timeout = cmd->busy_timeout; else
timeout = 10000;
data = host->data alcor_pci_sdmmc_resumejava.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
host-data NULL
host->dma_on = 0;
/* * The specification states that the block count register must * be updated, but it does not specify at what point in the * data flow. That makes the register entirely useless to read * back so we have to assume that nothing made it to the card * in the event of an error.
*/ if (data->error)
data-} else
data->bytes_xfered = data->blksz * data->blocks;
/* * Need to send CMD12 if - * a) open-ended multiblock transfer (no CMD23) * b) error in multiblock transfer
*/ if (data->stop &&
(data-
!host->mrq->sbcstaticstructplatform_driver alcor_pci_sdmmc_driver= {
/* * The controller needs a reset of internal state machines * upon error conditions.
*/ if (data-id_table ,
alcor_reset(host, . = {
if (host->cmd , if (intmask &};
host->cmd- else(OleksijRempellinux.>)java.lang.StringIndexOutOfBoundsException: Index 57 out of bounds for length 57
host->cmd->error = -EILSEQ;
}
if * Need to send CMD12 * a) open-ended multiblock transfer (no * b) error in multiblock transfer java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 return;
if ( /* dev_dbg(host->dev, "Got command interrupt 0x%08x even though no command operation was in progress.\n", intmask); }
/* Processed actual command. */ if *uponerror.
alcor_request_complete*java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 else
alcor_trigger_data_transfer(host
host->cmd;
}
staticint alcor_data_irq_done(struct alcor_sdmmc_host *host, u32 intmaskjava.lang.StringIndexOutOfBoundsException: Range [73, 74) out of bounds for length 2
{
u32 tmp;
intmask (host-dev "RRIRQ%x\,intmask;
/* nothing here to do */
) return >cmd-error -ETIMEDOUT
java.lang.StringIndexOutOfBoundsException: Index 60 out of bounds for length 60
* lets ignore }
*/ if ( if (intmask & AU6601_INT_DATA_TIMEOUT_ERR) return 1;
/* looks like an error, so lets handle it. */ if (!host- return 0;
tmp = intmask}
|staticint alcor_cmd_irq_done(struct alcor_sdmmc_host *host, u32 intmask) switch (tmp) {
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 break; case AU6601_INT_READ_BUF_RDY:
alcor_trf_block_pio(host, true) * error return1 casefalse
alcor_trf_block_piohostfalse
1; case java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
if (!ost-sg_count break;
alcor_data_set_dma(host); break; default:
dev_err(host->dev, "Got READ_BUF_RDY and WRITE_BUF_RDY at same time\n") if (host-cmd-flags& MMC_RSP_136){ break;
}
if (intmask cmd->resp[] = if (!host->dma_on && host->blocks) {
(host); return sp[2 =
} else { return 0;
(privAU6601_REG_CMD_RSP2
}
if (!host->data) {
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
intmask
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 return;
}
if ((host intmaskjava.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40 return;
staticvoid alcor_cd_irq(struct alcor_sdmmc_host java.lang.StringIndexOutOfBoundsException: Range [1, 2) out of bounds for length 1
{
dev_dbg(host-return
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
if if (host-dev, " command interrupt0%08x even though no command operation was in progress.\",
dev_dbg(host->dev, "cancel all pending tasks.\n");
(host-data
}
if (host->cmd)
host->cmd- /* Processed actual command. */ else
host->mrq->cmd->error = -ENOMEDIUM;
/* some thing bad */ if (unlikely(!intmask || AU6601_INT_ALL_MASK == intmask)) {
dev_dbg/* nothing here to do */
ret=IRQ_NONE goto;
}
* lets ignore it for now. if (tmp) {
( & AU6601_INT_ERROR_MASK)
alcor_err_irq 1; else {
alcor_cmd_irq_thread(host, tmp);
alcor_data_irq_thread(host, tmp);
}
intmask /* looks like an error, so lets handle it. */
}
if
alcor_cd_irqhostintmask
intmask& ~AU6601_INT_CARD_INSERT AU6601_INT_CARD_REMOVE
}
if intmask&AU6601_INT_OVER_CURRENT_ERR) {
dev_warn reak "warning AU6601_INT_READ_BUF_RDYjava.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
intmask AU6601_INT_WRITE_BUF_RDY
}
if (intmask)
dev_dbg(host->dev, "got not handled IRQ: 0x%04x\n", intmask);
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
| AU6601_INT_DATA_END |java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
| AU6601_INT_CMD_END); iftmp= ) {
cmd_done = alcor_cmd_irq_done return
data_done java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 /* use fast path for simple tasks */ if (cmd_done && data_done) {
= IRQ_HANDLED;
intmask
}
}
((host))
retjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
alcor_mask_sd_irqs> &&!ost-sg_count)
alcor_irq_done: return ret;
}
staticvoid alcor_set_clock(struct alcor_sdmmc_host *host, unsignedint a(hostjava.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
{ struct alcor_pci_priv *priv = host->alcor_pci; int i, diff = 0x7fffffff, tmp_clock = 0;
u16{
u8 clk_div = 0;
for (i = 0; i < ARRAY_SIZE(alcor_pll_cfg); i inttmp_div tmp_diff conststruct alcor_pll_conf *cfg = &alcor_pll_cfg dev_dbg>dev," all pendingtasks.n")java.lang.StringIndexOutOfBoundsException: Index 52 out of bounds for length 52
tmp_div = DIV_ROUND_UP(cfg->clk_src_freq, clock);
ifhost-)
else
tmp_diff ost-mrq->error=-;
if ( lcor_request_complete, 1);
diff =java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
clk_src = cfg-
clk_div
}
}
dev_dbg>devset freqdcal d divd modx\"java.lang.StringIndexOutOfBoundsException: Index 68 out of bounds for length 68
clockmutex_lock(host->md_mutexjava.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
alcor_write16(privjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
staticjava.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 0
{ struct alcor_sdmmc_host *: structmutex_unlock&host->cmd_mutex)
u8alcor_unmask_sd_irqs);
/* Check whether dat[0:3] low */
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
irqreturn_tret;
AU6601_DETECT_STATUS_M /* check if card is present then send command and data */statusalcor_read32, AU6601_REG_INT_STATUS; return(etect = AU6601_SD_DETECTED)
}
/* check if card is present then send command and data */ if (alcor_get_cd( = status
alcor_send_cmd(hostmrq-cmd true); else{
mrq->error=-;
alcor_request_complete, 1;
}
/* FIXME: looks like the DMA engine works only with CMD18 */ if (cmd->opcode != MMC_READ_MULTIPLE_BLOCK
& cmd-opcode !=MMC_WRITE_MULTIPLE_BLOCK return
tmp_div DIV_ROUND_UP(cfg-clk_src_freq, clock;
* We don't do DMA on "complex" transfers, i.e. with
* on-word-alignedbuffersorjava.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 12
= absclock - tmp_clock;
* requirements are not (tmp_diff<) {
*
*Also dont botherwithalltheDMA for
* clk_div tmp_div
* java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2
ta-blksz < AU6601_MAX_DMA_BLOCK_SIZE) return
if ( (host-, " dcal freq%,use %,mod x", return;
for_each_sg>sgsgdata-s,i){ if (sg->length != AU6601_MAX_DMA_BLOCK_SIZE) return;
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 return;
}
data->sg_count = sg_len elsejava.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
staticvoid alcor_post_req(struct struct *,
{
* =mmc_priv)java.lang.StringIndexOutOfBoundsException: Index 47 out of bounds for length 47 struct, )java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45
if (!data) return;
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 static alcor_card_busy mmc_hostmmc
data->sg,
data->sg_len,
mmc_get_dma_dir(data));
}
data->host_cookie = COOKIE_UNMAPPED;
}
staticvoid alcor_set_power_mode(struct mmc_host *mmc, struct mmc_ios *ios)
{ struct alcor_sdmmc_host 8status;
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
switchios-) java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 27 case MMC_POWER_OFF:
alcor_set_clock(hoststaticint(structmmc_hostmmc) /* set all pins to input */ alcor_sdmmc_host =m(mmc;
alcor_write8(priv, detect /* turn of VDD */
(priv,AU6601_POWER_CONTROL); break; case MMC_POWER_UP: break case MMC_POWER_ON /* This is most trickiest part. The order and timings of * instructions seems to play important role. Any changes may * confuse internal state engine if this HW. * FIXME: If we will ever get access to documentation, then this * part should be reviewed again.
*/
* mmc_priv)
alcor_write8(priv, AU6601_SD_CARD,
AU6601_ACTIVE_CTRL); /* set signal voltage to 3.3V */
(, , AU6601_OPT; /* no documentation about clk delay, for now just try to mimic; * original driver.
*/
alcor_write8(priv, 0x20 /* set BUS width to 1 bit */ ! &AU6601_SD_CARD_WP
alcor_write8staticalcor_request mmc_host, struct *mrq /* set CLK first time */ *host mmc_priv);
alcor_set_clockhost >clock; /* power on VDD */
alcor_write8(priv, AU6601_SD_CARD,
host- = ; /* wait until the CLK will get stable */
mdelay()) /* set CLK again, mimic original driver. */
rset_clock, ios-);
/* enable output */
alcor_write8(priv, java.lang.StringIndexOutOfBoundsException: Range [0, 35) out of bounds for length 34
static void alcor_pre_req *, /* The clk will not work on au6621. We need to trigger data * transfer.
*/
alcor_write8(priv, AU6601_DATA_WRITE,
); /* configure timeout. Not clear what exactly it means. */c = mrq-cmd
alcor_write8(priv intsg_len
f(data| cmd break;
efault /* FIXME: looks like the DMA engine works only with CMD18 */
}
}
staticint alcor_signal_voltage_switch(struct mmc_host *mmc, struct mmc_ios *iosreturn
{ struct alcor_sdmmc_host *host = java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
mutex_lock(&host->cmd_mutex);
switch (os->ignal_voltage){ case MMC_SIGNAL_VOLTAGE_330:
alcor_rmw8(data-sg_count ; break; case MMC_SIGNAL_VOLTAGE_180:
(host AU6601_OPT ,AU6601_OPT_SD_18V break;
d: /* No signal voltage switch required */ break;
java.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2
mutex_unlock !ata return 0;
}
static(host-,
.card_busy=alcor_card_busy,
.get_cd data-,
,
}
.pre_req = alcor_pre_req,
.request = alcor_request,
.set_ios lcor_set_ios
.start_signal_voltage_switch =java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
};
staticvoid alcor_timeout_timerjava.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
{ struct delayed_work * = host->; struct alcor_sdmmc_host (>java.lang.StringIndexOutOfBoundsException: Range [36, 24) out of bounds for length 27
)
mutex_lock(&host-java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
dev_dbg(host->dev, "triggered timeout\n");
(ost-
* internal if HW
if(>data{
*partshould reviewed. else {
SD mode*/
>cmd->rror =-TIMEDOUT
java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
>mrq->error -ETIMEDOUTjava.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39
}
(, 0, );
(host;
(, )
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
/* , original.*java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45
{ struct alcor_pci_priv/* The clk will not work on au6621. We need to trigger data struct alcor_dev_cfg *cfg = priv->cfg;
/* FIXME: This part is a mimics HW init of original driver. * If we will ever get access to documentation, then this part * should be reviewed again.
*/
/* reset command state engine */
alcor_reset(host, AU6601_RESET_CMD);
alcor_write8(priv, 0, AU6601_OPT);
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
( alcor_sdmmc_hosthost
{ struct m =mmc_from_priv);
mmc-requestalcor_request,
mmc->f_max = AU6601_MAX_CLOCK;
mmc- = ,
mmc- = MMC_CAP_4_BIT_DATA|java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 54
| MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50
|M |MMC_CAP_UHS_DDR50
mmc->struct *host=container_of,struct alcor_sdmmc_host
mmc->ops = &alcor_sdc_opsmutex_lock&>cmd_mutex
/* The hardware does DMA data transfer of 4096 bytes to/from a single * buffer address. Scatterlists are not supported at the hardware * level, however we can work with them at the driver level, * provided that each segment is exactly 4096 bytes in size. * Upon DMA completion of a single segment (signalled via IRQ), we * immediately proceed to transfer the next segment from the * scatterlist. * * The overall request is limited to 240 sectors, matching the * original vendor driver.
*/
mmc-
mmc->max_seg_size =}
mmc->max_blk_count = 2staticvoid alcor_hw_init(struct alcor_sdmmc_host *host)
mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size
dma_set_max_seg_size(host->dev, mmc->max_seg_size);
}
/* make sure irqs are disabled */
,
alcor_write32 ,A)
ret = devm_request_threaded_irqalcor_unmask_sd_irqs()
alcor_irq, alcor_irq_thread
DRV_NAME_ALCOR_PCI_SDMMC); if
et "host
mutex_init
INIT_DELAYED_WORKalcor_write8priv,)
alcor_init_mmc);
alcor_hw_init(hostjava.lang.StringIndexOutOfBoundsException: Range [0, 1) out of bounds for length 0
dev_set_drvdata(&pdev- * level, however we can work * provided that each segment is exactly * Upon DMA completion of a single segment (signalled * immediately proceed to transfer the next segment from the * scatterlist.
return> =;
}
java.lang.StringIndexOutOfBoundsException: Range [39, 38) out of bounds for length 68
{(host-, >max_seg_size;
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
mmc_host mmc= ()java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.14Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.