Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-elphel
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
linux-elphel
Commits
fd4f2e1d
Commit
fd4f2e1d
authored
Jul 23, 2019
by
Oleg Dzhimiev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
updated to current version
parent
2455c447
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
545 additions
and
349 deletions
+545
-349
sdhci.c
src/drivers/mmc/host/sdhci.c
+545
-349
No files found.
src/drivers/mmc/host/sdhci.c
View file @
fd4f2e1d
...
@@ -14,6 +14,7 @@
...
@@ -14,6 +14,7 @@
*/
*/
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/ktime.h>
#include <linux/highmem.h>
#include <linux/highmem.h>
#include <linux/io.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/module.h>
...
@@ -22,6 +23,7 @@
...
@@ -22,6 +23,7 @@
#include <linux/scatterlist.h>
#include <linux/scatterlist.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/leds.h>
#include <linux/leds.h>
...
@@ -36,7 +38,10 @@
...
@@ -36,7 +38,10 @@
#define DRIVER_NAME "sdhci"
#define DRIVER_NAME "sdhci"
#define DBG(f, x...) \
#define DBG(f, x...) \
pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
pr_debug("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
#define SDHCI_DUMP(f, x...) \
pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
#define MAX_TUNING_LOOP 40
#define MAX_TUNING_LOOP 40
...
@@ -47,61 +52,68 @@ static void sdhci_finish_data(struct sdhci_host *);
...
@@ -47,61 +52,68 @@ static void sdhci_finish_data(struct sdhci_host *);
static
void
sdhci_enable_preset_value
(
struct
sdhci_host
*
host
,
bool
enable
);
static
void
sdhci_enable_preset_value
(
struct
sdhci_host
*
host
,
bool
enable
);
static
void
sdhci_dumpregs
(
struct
sdhci_host
*
host
)
void
sdhci_dumpregs
(
struct
sdhci_host
*
host
)
{
{
pr_err
(
DRIVER_NAME
": =========== REGISTER DUMP (%s)===========
\n
"
,
SDHCI_DUMP
(
"============ SDHCI REGISTER DUMP ===========
\n
"
);
mmc_hostname
(
host
->
mmc
));
SDHCI_DUMP
(
"Sys addr: 0x%08x | Version: 0x%08x
\n
"
,
pr_err
(
DRIVER_NAME
": Sys addr: 0x%08x | Version: 0x%08x
\n
"
,
sdhci_readl
(
host
,
SDHCI_DMA_ADDRESS
),
sdhci_readl
(
host
,
SDHCI_DMA_ADDRESS
),
sdhci_readw
(
host
,
SDHCI_HOST_VERSION
));
sdhci_readw
(
host
,
SDHCI_HOST_VERSION
));
SDHCI_DUMP
(
"Blk size: 0x%08x | Blk cnt: 0x%08x
\n
"
,
pr_err
(
DRIVER_NAME
": Blk size: 0x%08x | Blk cnt: 0x%08x
\n
"
,
sdhci_readw
(
host
,
SDHCI_BLOCK_SIZE
),
sdhci_readw
(
host
,
SDHCI_BLOCK_SIZE
),
sdhci_readw
(
host
,
SDHCI_BLOCK_COUNT
));
sdhci_readw
(
host
,
SDHCI_BLOCK_COUNT
));
SDHCI_DUMP
(
"Argument: 0x%08x | Trn mode: 0x%08x
\n
"
,
pr_err
(
DRIVER_NAME
": Argument: 0x%08x | Trn mode: 0x%08x
\n
"
,
sdhci_readl
(
host
,
SDHCI_ARGUMENT
),
sdhci_readl
(
host
,
SDHCI_ARGUMENT
),
sdhci_readw
(
host
,
SDHCI_TRANSFER_MODE
));
sdhci_readw
(
host
,
SDHCI_TRANSFER_MODE
));
SDHCI_DUMP
(
"Present: 0x%08x | Host ctl: 0x%08x
\n
"
,
pr_err
(
DRIVER_NAME
": Present: 0x%08x | Host ctl: 0x%08x
\n
"
,
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
),
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
),
sdhci_readb
(
host
,
SDHCI_HOST_CONTROL
));
sdhci_readb
(
host
,
SDHCI_HOST_CONTROL
));
SDHCI_DUMP
(
"Power: 0x%08x | Blk gap: 0x%08x
\n
"
,
pr_err
(
DRIVER_NAME
": Power: 0x%08x | Blk gap: 0x%08x
\n
"
,
sdhci_readb
(
host
,
SDHCI_POWER_CONTROL
),
sdhci_readb
(
host
,
SDHCI_POWER_CONTROL
),
sdhci_readb
(
host
,
SDHCI_BLOCK_GAP_CONTROL
));
sdhci_readb
(
host
,
SDHCI_BLOCK_GAP_CONTROL
));
SDHCI_DUMP
(
"Wake-up: 0x%08x | Clock: 0x%08x
\n
"
,
pr_err
(
DRIVER_NAME
": Wake-up: 0x%08x | Clock: 0x%08x
\n
"
,
sdhci_readb
(
host
,
SDHCI_WAKE_UP_CONTROL
),
sdhci_readb
(
host
,
SDHCI_WAKE_UP_CONTROL
),
sdhci_readw
(
host
,
SDHCI_CLOCK_CONTROL
));
sdhci_readw
(
host
,
SDHCI_CLOCK_CONTROL
));
SDHCI_DUMP
(
"Timeout: 0x%08x | Int stat: 0x%08x
\n
"
,
pr_err
(
DRIVER_NAME
": Timeout: 0x%08x | Int stat: 0x%08x
\n
"
,
sdhci_readb
(
host
,
SDHCI_TIMEOUT_CONTROL
),
sdhci_readb
(
host
,
SDHCI_TIMEOUT_CONTROL
),
sdhci_readl
(
host
,
SDHCI_INT_STATUS
));
sdhci_readl
(
host
,
SDHCI_INT_STATUS
));
SDHCI_DUMP
(
"Int enab: 0x%08x | Sig enab: 0x%08x
\n
"
,
pr_err
(
DRIVER_NAME
": Int enab: 0x%08x | Sig enab: 0x%08x
\n
"
,
sdhci_readl
(
host
,
SDHCI_INT_ENABLE
),
sdhci_readl
(
host
,
SDHCI_INT_ENABLE
),
sdhci_readl
(
host
,
SDHCI_SIGNAL_ENABLE
));
sdhci_readl
(
host
,
SDHCI_SIGNAL_ENABLE
));
SDHCI_DUMP
(
"AC12 err: 0x%08x | Slot int: 0x%08x
\n
"
,
pr_err
(
DRIVER_NAME
": AC12 err: 0x%08x | Slot int: 0x%08x
\n
"
,
sdhci_readw
(
host
,
SDHCI_ACMD12_ERR
),
sdhci_readw
(
host
,
SDHCI_ACMD12_ERR
),
sdhci_readw
(
host
,
SDHCI_SLOT_INT_STATUS
));
sdhci_readw
(
host
,
SDHCI_SLOT_INT_STATUS
));
SDHCI_DUMP
(
"Caps: 0x%08x | Caps_1: 0x%08x
\n
"
,
pr_err
(
DRIVER_NAME
": Caps: 0x%08x | Caps_1: 0x%08x
\n
"
,
sdhci_readl
(
host
,
SDHCI_CAPABILITIES
),
sdhci_readl
(
host
,
SDHCI_CAPABILITIES
),
sdhci_readl
(
host
,
SDHCI_CAPABILITIES_1
));
sdhci_readl
(
host
,
SDHCI_CAPABILITIES_1
));
SDHCI_DUMP
(
"Cmd: 0x%08x | Max curr: 0x%08x
\n
"
,
pr_err
(
DRIVER_NAME
": Cmd: 0x%08x | Max curr: 0x%08x
\n
"
,
sdhci_readw
(
host
,
SDHCI_COMMAND
),
sdhci_readw
(
host
,
SDHCI_COMMAND
),
sdhci_readl
(
host
,
SDHCI_MAX_CURRENT
));
sdhci_readl
(
host
,
SDHCI_MAX_CURRENT
));
SDHCI_DUMP
(
"Resp[0]: 0x%08x | Resp[1]: 0x%08x
\n
"
,
pr_err
(
DRIVER_NAME
": Host ctl2: 0x%08x
\n
"
,
sdhci_readl
(
host
,
SDHCI_RESPONSE
),
sdhci_readw
(
host
,
SDHCI_HOST_CONTROL2
));
sdhci_readl
(
host
,
SDHCI_RESPONSE
+
4
));
SDHCI_DUMP
(
"Resp[2]: 0x%08x | Resp[3]: 0x%08x
\n
"
,
sdhci_readl
(
host
,
SDHCI_RESPONSE
+
8
),
sdhci_readl
(
host
,
SDHCI_RESPONSE
+
12
));
SDHCI_DUMP
(
"Host ctl2: 0x%08x
\n
"
,
sdhci_readw
(
host
,
SDHCI_HOST_CONTROL2
));
if
(
host
->
flags
&
SDHCI_USE_ADMA
)
{
if
(
host
->
flags
&
SDHCI_USE_ADMA
)
{
if
(
host
->
flags
&
SDHCI_USE_64_BIT_DMA
)
if
(
host
->
flags
&
SDHCI_USE_64_BIT_DMA
)
{
pr_err
(
DRIVER_NAME
": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x
\n
"
,
SDHCI_DUMP
(
"ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x
\n
"
,
readl
(
host
->
ioaddr
+
SDHCI_ADMA_ERROR
),
sdhci_readl
(
host
,
SDHCI_ADMA_ERROR
),
readl
(
host
->
ioaddr
+
SDHCI_ADMA_ADDRESS_HI
),
sdhci_readl
(
host
,
SDHCI_ADMA_ADDRESS_HI
),
readl
(
host
->
ioaddr
+
SDHCI_ADMA_ADDRESS
));
sdhci_readl
(
host
,
SDHCI_ADMA_ADDRESS
));
else
}
else
{
pr_err
(
DRIVER_NAME
": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x
\n
"
,
SDHCI_DUMP
(
"ADMA Err: 0x%08x | ADMA Ptr: 0x%08x
\n
"
,
readl
(
host
->
ioaddr
+
SDHCI_ADMA_ERROR
),
sdhci_readl
(
host
,
SDHCI_ADMA_ERROR
),
readl
(
host
->
ioaddr
+
SDHCI_ADMA_ADDRESS
));
sdhci_readl
(
host
,
SDHCI_ADMA_ADDRESS
));
}
}
}
pr_err
(
DRIVER_NAME
":
===========================================
\n
"
);
SDHCI_DUMP
(
"=
===========================================
\n
"
);
}
}
EXPORT_SYMBOL_GPL
(
sdhci_dumpregs
);
/*****************************************************************************\
/*****************************************************************************\
* *
* *
...
@@ -124,8 +136,8 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
...
@@ -124,8 +136,8 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
if
(
enable
)
{
if
(
enable
)
{
present
=
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
)
&
present
=
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
)
&
// Elphel
// Elphel
//
SDHCI_CARD_PRESENT;
//
SDHCI_CARD_PRESENT;
SDHCI_ANY_PRESENT
;
SDHCI_ANY_PRESENT
;
host
->
ier
|=
present
?
SDHCI_INT_CARD_REMOVE
:
host
->
ier
|=
present
?
SDHCI_INT_CARD_REMOVE
:
...
@@ -166,7 +178,7 @@ static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
...
@@ -166,7 +178,7 @@ static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
void
sdhci_reset
(
struct
sdhci_host
*
host
,
u8
mask
)
void
sdhci_reset
(
struct
sdhci_host
*
host
,
u8
mask
)
{
{
unsigned
long
timeout
;
ktime_t
timeout
;
sdhci_writeb
(
host
,
mask
,
SDHCI_SOFTWARE_RESET
);
sdhci_writeb
(
host
,
mask
,
SDHCI_SOFTWARE_RESET
);
...
@@ -178,18 +190,17 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
...
@@ -178,18 +190,17 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
}
}
/* Wait max 100 ms */
/* Wait max 100 ms */
timeout
=
100
;
timeout
=
ktime_add_ms
(
ktime_get
(),
100
)
;
/* hw clears the bit when it's done */
/* hw clears the bit when it's done */
while
(
sdhci_readb
(
host
,
SDHCI_SOFTWARE_RESET
)
&
mask
)
{
while
(
sdhci_readb
(
host
,
SDHCI_SOFTWARE_RESET
)
&
mask
)
{
if
(
timeout
==
0
)
{
if
(
ktime_after
(
ktime_get
(),
timeout
)
)
{
pr_err
(
"%s: Reset 0x%x never completed.
\n
"
,
pr_err
(
"%s: Reset 0x%x never completed.
\n
"
,
mmc_hostname
(
host
->
mmc
),
(
int
)
mask
);
mmc_hostname
(
host
->
mmc
),
(
int
)
mask
);
sdhci_dumpregs
(
host
);
sdhci_dumpregs
(
host
);
return
;
return
;
}
}
timeout
--
;
udelay
(
10
);
mdelay
(
1
);
}
}
}
}
EXPORT_SYMBOL_GPL
(
sdhci_reset
);
EXPORT_SYMBOL_GPL
(
sdhci_reset
);
...
@@ -198,13 +209,12 @@ static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
...
@@ -198,13 +209,12 @@ static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
{
{
if
(
host
->
quirks
&
SDHCI_QUIRK_NO_CARD_NO_RESET
)
{
if
(
host
->
quirks
&
SDHCI_QUIRK_NO_CARD_NO_RESET
)
{
// Elphel: this is current code
// Elphel: this is current code
/*
/*
struct mmc_host *mmc = host->mmc;
struct mmc_host *mmc = host->mmc;
if (!mmc->ops->get_cd(mmc))
if (!mmc->ops->get_cd(mmc))
return;
return;
*/
*/
// Elphel: this is old code
// Elphel: this is old code
if
(
!
(
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
)
&
if
(
!
(
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
)
&
SDHCI_ANY_PRESENT
)){
SDHCI_ANY_PRESENT
)){
...
@@ -225,15 +235,8 @@ static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
...
@@ -225,15 +235,8 @@ static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
}
}
}
}
static
void
sdhci_
init
(
struct
sdhci_host
*
host
,
int
sof
t
)
static
void
sdhci_
set_default_irqs
(
struct
sdhci_host
*
hos
t
)
{
{
struct
mmc_host
*
mmc
=
host
->
mmc
;
if
(
soft
)
sdhci_do_reset
(
host
,
SDHCI_RESET_CMD
|
SDHCI_RESET_DATA
);
else
sdhci_do_reset
(
host
,
SDHCI_RESET_ALL
);
host
->
ier
=
SDHCI_INT_BUS_POWER
|
SDHCI_INT_DATA_END_BIT
|
host
->
ier
=
SDHCI_INT_BUS_POWER
|
SDHCI_INT_DATA_END_BIT
|
SDHCI_INT_DATA_CRC
|
SDHCI_INT_DATA_TIMEOUT
|
SDHCI_INT_DATA_CRC
|
SDHCI_INT_DATA_TIMEOUT
|
SDHCI_INT_INDEX
|
SDHCI_INT_END_BIT
|
SDHCI_INT_CRC
|
SDHCI_INT_INDEX
|
SDHCI_INT_END_BIT
|
SDHCI_INT_CRC
|
...
@@ -246,6 +249,20 @@ static void sdhci_init(struct sdhci_host *host, int soft)
...
@@ -246,6 +249,20 @@ static void sdhci_init(struct sdhci_host *host, int soft)
sdhci_writel
(
host
,
host
->
ier
,
SDHCI_INT_ENABLE
);
sdhci_writel
(
host
,
host
->
ier
,
SDHCI_INT_ENABLE
);
sdhci_writel
(
host
,
host
->
ier
,
SDHCI_SIGNAL_ENABLE
);
sdhci_writel
(
host
,
host
->
ier
,
SDHCI_SIGNAL_ENABLE
);
}
static
void
sdhci_init
(
struct
sdhci_host
*
host
,
int
soft
)
{
struct
mmc_host
*
mmc
=
host
->
mmc
;
if
(
soft
)
sdhci_do_reset
(
host
,
SDHCI_RESET_CMD
|
SDHCI_RESET_DATA
);
else
sdhci_do_reset
(
host
,
SDHCI_RESET_ALL
);
sdhci_set_default_irqs
(
host
);
host
->
cqe_on
=
false
;
if
(
soft
)
{
if
(
soft
)
{
/* force clock reconfiguration */
/* force clock reconfiguration */
...
@@ -495,8 +512,7 @@ static int sdhci_pre_dma_transfer(struct sdhci_host *host,
...
@@ -495,8 +512,7 @@ static int sdhci_pre_dma_transfer(struct sdhci_host *host,
return
data
->
sg_count
;
return
data
->
sg_count
;
sg_count
=
dma_map_sg
(
mmc_dev
(
host
->
mmc
),
data
->
sg
,
data
->
sg_len
,
sg_count
=
dma_map_sg
(
mmc_dev
(
host
->
mmc
),
data
->
sg
,
data
->
sg_len
,
data
->
flags
&
MMC_DATA_WRITE
?
mmc_get_dma_dir
(
data
));
DMA_TO_DEVICE
:
DMA_FROM_DEVICE
);
if
(
sg_count
==
0
)
if
(
sg_count
==
0
)
return
-
ENOSPC
;
return
-
ENOSPC
;
...
@@ -725,8 +741,8 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
...
@@ -725,8 +741,8 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
}
}
if
(
count
>=
0xF
)
{
if
(
count
>=
0xF
)
{
DBG
(
"
%s:
Too large timeout 0x%x requested for CMD%d!
\n
"
,
DBG
(
"Too large timeout 0x%x requested for CMD%d!
\n
"
,
mmc_hostname
(
host
->
mmc
),
count
,
cmd
->
opcode
);
count
,
cmd
->
opcode
);
count
=
0xE
;
count
=
0xE
;
}
}
...
@@ -891,8 +907,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
...
@@ -891,8 +907,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
sdhci_set_transfer_irqs
(
host
);
sdhci_set_transfer_irqs
(
host
);
/* Set the DMA boundary value and block size */
/* Set the DMA boundary value and block size */
sdhci_writew
(
host
,
SDHCI_MAKE_BLKSZ
(
SDHCI_DEFAULT_BOUNDARY_ARG
,
sdhci_writew
(
host
,
SDHCI_MAKE_BLKSZ
(
host
->
sdma_boundary
,
data
->
blksz
)
,
data
->
blksz
),
SDHCI_BLOCK_SIZE
);
SDHCI_BLOCK_SIZE
);
sdhci_writew
(
host
,
data
->
blocks
,
SDHCI_BLOCK_COUNT
);
sdhci_writew
(
host
,
data
->
blocks
,
SDHCI_BLOCK_COUNT
);
}
}
...
@@ -1167,24 +1183,35 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
...
@@ -1167,24 +1183,35 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
}
}
EXPORT_SYMBOL_GPL
(
sdhci_send_command
);
EXPORT_SYMBOL_GPL
(
sdhci_send_command
);
static
void
sdhci_read_rsp_136
(
struct
sdhci_host
*
host
,
struct
mmc_command
*
cmd
)
{
int
i
,
reg
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
reg
=
SDHCI_RESPONSE
+
(
3
-
i
)
*
4
;
cmd
->
resp
[
i
]
=
sdhci_readl
(
host
,
reg
);
}
if
(
host
->
quirks2
&
SDHCI_QUIRK2_RSP_136_HAS_CRC
)
return
;
/* CRC is stripped so we need to do some shifting */
for
(
i
=
0
;
i
<
4
;
i
++
)
{
cmd
->
resp
[
i
]
<<=
8
;
if
(
i
!=
3
)
cmd
->
resp
[
i
]
|=
cmd
->
resp
[
i
+
1
]
>>
24
;
}
}
static
void
sdhci_finish_command
(
struct
sdhci_host
*
host
)
static
void
sdhci_finish_command
(
struct
sdhci_host
*
host
)
{
{
struct
mmc_command
*
cmd
=
host
->
cmd
;
struct
mmc_command
*
cmd
=
host
->
cmd
;
int
i
;
host
->
cmd
=
NULL
;
host
->
cmd
=
NULL
;
if
(
cmd
->
flags
&
MMC_RSP_PRESENT
)
{
if
(
cmd
->
flags
&
MMC_RSP_PRESENT
)
{
if
(
cmd
->
flags
&
MMC_RSP_136
)
{
if
(
cmd
->
flags
&
MMC_RSP_136
)
{
/* CRC is stripped so we need to do some shifting. */
sdhci_read_rsp_136
(
host
,
cmd
);
for
(
i
=
0
;
i
<
4
;
i
++
)
{
cmd
->
resp
[
i
]
=
sdhci_readl
(
host
,
SDHCI_RESPONSE
+
(
3
-
i
)
*
4
)
<<
8
;
if
(
i
!=
3
)
cmd
->
resp
[
i
]
|=
sdhci_readb
(
host
,
SDHCI_RESPONSE
+
(
3
-
i
)
*
4
-
1
);
}
}
else
{
}
else
{
cmd
->
resp
[
0
]
=
sdhci_readl
(
host
,
SDHCI_RESPONSE
);
cmd
->
resp
[
0
]
=
sdhci_readl
(
host
,
SDHCI_RESPONSE
);
}
}
...
@@ -1354,40 +1381,45 @@ clock_set:
...
@@ -1354,40 +1381,45 @@ clock_set:
}
}
EXPORT_SYMBOL_GPL
(
sdhci_calc_clk
);
EXPORT_SYMBOL_GPL
(
sdhci_calc_clk
);
void
sdhci_
set_clock
(
struct
sdhci_host
*
host
,
unsigned
int
cloc
k
)
void
sdhci_
enable_clk
(
struct
sdhci_host
*
host
,
u16
cl
k
)
{
{
u16
clk
;
ktime_t
timeout
;
unsigned
long
timeout
;
host
->
mmc
->
actual_clock
=
0
;
sdhci_writew
(
host
,
0
,
SDHCI_CLOCK_CONTROL
);
if
(
clock
==
0
)
return
;
clk
=
sdhci_calc_clk
(
host
,
clock
,
&
host
->
mmc
->
actual_clock
);
clk
|=
SDHCI_CLOCK_INT_EN
;
clk
|=
SDHCI_CLOCK_INT_EN
;
sdhci_writew
(
host
,
clk
,
SDHCI_CLOCK_CONTROL
);
sdhci_writew
(
host
,
clk
,
SDHCI_CLOCK_CONTROL
);
/* Wait max 20 ms */
/* Wait max 20 ms */
timeout
=
20
;
timeout
=
ktime_add_ms
(
ktime_get
(),
20
)
;
while
(
!
((
clk
=
sdhci_readw
(
host
,
SDHCI_CLOCK_CONTROL
))
while
(
!
((
clk
=
sdhci_readw
(
host
,
SDHCI_CLOCK_CONTROL
))
&
SDHCI_CLOCK_INT_STABLE
))
{
&
SDHCI_CLOCK_INT_STABLE
))
{
if
(
timeout
==
0
)
{
if
(
ktime_after
(
ktime_get
(),
timeout
)
)
{
pr_err
(
"%s: Internal clock never stabilised.
\n
"
,
pr_err
(
"%s: Internal clock never stabilised.
\n
"
,
mmc_hostname
(
host
->
mmc
));
mmc_hostname
(
host
->
mmc
));
sdhci_dumpregs
(
host
);
sdhci_dumpregs
(
host
);
return
;
return
;
}
}
timeout
--
;
udelay
(
10
);
mdelay
(
1
);
}
}
clk
|=
SDHCI_CLOCK_CARD_EN
;
clk
|=
SDHCI_CLOCK_CARD_EN
;
sdhci_writew
(
host
,
clk
,
SDHCI_CLOCK_CONTROL
);
sdhci_writew
(
host
,
clk
,
SDHCI_CLOCK_CONTROL
);
}
}
EXPORT_SYMBOL_GPL
(
sdhci_enable_clk
);
void
sdhci_set_clock
(
struct
sdhci_host
*
host
,
unsigned
int
clock
)
{
u16
clk
;
host
->
mmc
->
actual_clock
=
0
;
sdhci_writew
(
host
,
0
,
SDHCI_CLOCK_CONTROL
);
if
(
clock
==
0
)
return
;
clk
=
sdhci_calc_clk
(
host
,
clock
,
&
host
->
mmc
->
actual_clock
);
sdhci_enable_clk
(
host
,
clk
);
}
EXPORT_SYMBOL_GPL
(
sdhci_set_clock
);
EXPORT_SYMBOL_GPL
(
sdhci_set_clock
);
static
void
sdhci_set_power_reg
(
struct
sdhci_host
*
host
,
unsigned
char
mode
,
static
void
sdhci_set_power_reg
(
struct
sdhci_host
*
host
,
unsigned
char
mode
,
...
@@ -1395,9 +1427,7 @@ static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
...
@@ -1395,9 +1427,7 @@ static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
{
{
struct
mmc_host
*
mmc
=
host
->
mmc
;
struct
mmc_host
*
mmc
=
host
->
mmc
;
spin_unlock_irq
(
&
host
->
lock
);
mmc_regulator_set_ocr
(
mmc
,
mmc
->
supply
.
vmmc
,
vdd
);
mmc_regulator_set_ocr
(
mmc
,
mmc
->
supply
.
vmmc
,
vdd
);
spin_lock_irq
(
&
host
->
lock
);
if
(
mode
!=
MMC_POWER_OFF
)
if
(
mode
!=
MMC_POWER_OFF
)
sdhci_writeb
(
host
,
SDHCI_POWER_ON
,
SDHCI_POWER_CONTROL
);
sdhci_writeb
(
host
,
SDHCI_POWER_ON
,
SDHCI_POWER_CONTROL
);
...
@@ -1545,10 +1575,9 @@ void sdhci_set_bus_width(struct sdhci_host *host, int width)
...
@@ -1545,10 +1575,9 @@ void sdhci_set_bus_width(struct sdhci_host *host, int width)
ctrl
=
sdhci_readb
(
host
,
SDHCI_HOST_CONTROL
);
ctrl
=
sdhci_readb
(
host
,
SDHCI_HOST_CONTROL
);
if
(
width
==
MMC_BUS_WIDTH_8
)
{
if
(
width
==
MMC_BUS_WIDTH_8
)
{
ctrl
&=
~
SDHCI_CTRL_4BITBUS
;
ctrl
&=
~
SDHCI_CTRL_4BITBUS
;
if
(
host
->
version
>=
SDHCI_SPEC_300
)
ctrl
|=
SDHCI_CTRL_8BITBUS
;
ctrl
|=
SDHCI_CTRL_8BITBUS
;
}
else
{
}
else
{
if
(
host
->
version
>=
SDHCI_SPEC_300
)
if
(
host
->
mmc
->
caps
&
MMC_CAP_8_BIT_DATA
)
ctrl
&=
~
SDHCI_CTRL_8BITBUS
;
ctrl
&=
~
SDHCI_CTRL_8BITBUS
;
if
(
width
==
MMC_BUS_WIDTH_4
)
if
(
width
==
MMC_BUS_WIDTH_4
)
ctrl
|=
SDHCI_CTRL_4BITBUS
;
ctrl
|=
SDHCI_CTRL_4BITBUS
;
...
@@ -1584,16 +1613,15 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
...
@@ -1584,16 +1613,15 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
}
}
EXPORT_SYMBOL_GPL
(
sdhci_set_uhs_signaling
);
EXPORT_SYMBOL_GPL
(
sdhci_set_uhs_signaling
);
static
void
sdhci_set_ios
(
struct
mmc_host
*
mmc
,
struct
mmc_ios
*
ios
)
void
sdhci_set_ios
(
struct
mmc_host
*
mmc
,
struct
mmc_ios
*
ios
)
{
{
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
unsigned
long
flags
;
u8
ctrl
;
u8
ctrl
;
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
if
(
ios
->
power_mode
==
MMC_POWER_UNDEFINED
)
return
;
if
(
host
->
flags
&
SDHCI_DEVICE_DEAD
)
{
if
(
host
->
flags
&
SDHCI_DEVICE_DEAD
)
{
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
if
(
!
IS_ERR
(
mmc
->
supply
.
vmmc
)
&&
if
(
!
IS_ERR
(
mmc
->
supply
.
vmmc
)
&&
ios
->
power_mode
==
MMC_POWER_OFF
)
ios
->
power_mode
==
MMC_POWER_OFF
)
mmc_regulator_set_ocr
(
mmc
,
mmc
->
supply
.
vmmc
,
0
);
mmc_regulator_set_ocr
(
mmc
,
mmc
->
supply
.
vmmc
,
0
);
...
@@ -1643,26 +1671,24 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
...
@@ -1643,26 +1671,24 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
ctrl
=
sdhci_readb
(
host
,
SDHCI_HOST_CONTROL
);
ctrl
=
sdhci_readb
(
host
,
SDHCI_HOST_CONTROL
);
if
((
ios
->
timing
==
MMC_TIMING_SD_HS
||
if
(
!
(
host
->
quirks
&
SDHCI_QUIRK_NO_HISPD_BIT
))
{
ios
->
timing
==
MMC_TIMING_MMC_HS
)
if
(
ios
->
timing
==
MMC_TIMING_SD_HS
||
&&
!
(
host
->
quirks
&
SDHCI_QUIRK_NO_HISPD_BIT
))
ios
->
timing
==
MMC_TIMING_MMC_HS
||
ctrl
|=
SDHCI_CTRL_HISPD
;
ios
->
timing
==
MMC_TIMING_MMC_HS400
||
else
ios
->
timing
==
MMC_TIMING_MMC_HS200
||
ctrl
&=
~
SDHCI_CTRL_HISPD
;
ios
->
timing
==
MMC_TIMING_MMC_DDR52
||
ios
->
timing
==
MMC_TIMING_UHS_SDR50
||
ios
->
timing
==
MMC_TIMING_UHS_SDR104
||
ios
->
timing
==
MMC_TIMING_UHS_DDR50
||
ios
->
timing
==
MMC_TIMING_UHS_SDR25
)
ctrl
|=
SDHCI_CTRL_HISPD
;
else
ctrl
&=
~
SDHCI_CTRL_HISPD
;
}
if
(
host
->
version
>=
SDHCI_SPEC_300
)
{
if
(
host
->
version
>=
SDHCI_SPEC_300
)
{
u16
clk
,
ctrl_2
;
u16
clk
,
ctrl_2
;
/* In case of UHS-I modes, set High Speed Enable */
if
((
ios
->
timing
==
MMC_TIMING_MMC_HS400
)
||
(
ios
->
timing
==
MMC_TIMING_MMC_HS200
)
||
(
ios
->
timing
==
MMC_TIMING_MMC_DDR52
)
||
(
ios
->
timing
==
MMC_TIMING_UHS_SDR50
)
||
(
ios
->
timing
==
MMC_TIMING_UHS_SDR104
)
||
(
ios
->
timing
==
MMC_TIMING_UHS_DDR50
)
||
(
ios
->
timing
==
MMC_TIMING_UHS_SDR25
))
ctrl
|=
SDHCI_CTRL_HISPD
;
if
(
!
host
->
preset_enabled
)
{
if
(
!
host
->
preset_enabled
)
{
sdhci_writeb
(
host
,
ctrl
,
SDHCI_HOST_CONTROL
);
sdhci_writeb
(
host
,
ctrl
,
SDHCI_HOST_CONTROL
);
/*
/*
...
@@ -1742,8 +1768,8 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
...
@@ -1742,8 +1768,8 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
sdhci_do_reset
(
host
,
SDHCI_RESET_CMD
|
SDHCI_RESET_DATA
);
sdhci_do_reset
(
host
,
SDHCI_RESET_CMD
|
SDHCI_RESET_DATA
);
mmiowb
();
mmiowb
();
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
}
}
EXPORT_SYMBOL_GPL
(
sdhci_set_ios
);
static
int
sdhci_get_cd
(
struct
mmc_host
*
mmc
)
static
int
sdhci_get_cd
(
struct
mmc_host
*
mmc
)
{
{
...
@@ -1839,11 +1865,14 @@ static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
...
@@ -1839,11 +1865,14 @@ static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
}
}
}
}
static
void
sdhci_enable_sdio_irq
(
struct
mmc_host
*
mmc
,
int
enable
)
void
sdhci_enable_sdio_irq
(
struct
mmc_host
*
mmc
,
int
enable
)
{
{
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
unsigned
long
flags
;
unsigned
long
flags
;
if
(
enable
)
pm_runtime_get_noresume
(
host
->
mmc
->
parent
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
if
(
enable
)
if
(
enable
)
host
->
flags
|=
SDHCI_SDIO_IRQ_ENABLED
;
host
->
flags
|=
SDHCI_SDIO_IRQ_ENABLED
;
...
@@ -1852,10 +1881,14 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
...
@@ -1852,10 +1881,14 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
sdhci_enable_sdio_irq_nolock
(
host
,
enable
);
sdhci_enable_sdio_irq_nolock
(
host
,
enable
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
if
(
!
enable
)
pm_runtime_put_noidle
(
host
->
mmc
->
parent
);
}
}
EXPORT_SYMBOL_GPL
(
sdhci_enable_sdio_irq
);
static
int
sdhci_start_signal_voltage_switch
(
struct
mmc_host
*
mmc
,
int
sdhci_start_signal_voltage_switch
(
struct
mmc_host
*
mmc
,
struct
mmc_ios
*
ios
)
struct
mmc_ios
*
ios
)
{
{
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
u16
ctrl
;
u16
ctrl
;
...
@@ -1947,6 +1980,7 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
...
@@ -1947,6 +1980,7 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
return
0
;
return
0
;
}
}
}
}
EXPORT_SYMBOL_GPL
(
sdhci_start_signal_voltage_switch
);
static
int
sdhci_card_busy
(
struct
mmc_host
*
mmc
)
static
int
sdhci_card_busy
(
struct
mmc_host
*
mmc
)
{
{
...
@@ -1971,20 +2005,161 @@ static int sdhci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
...
@@ -1971,20 +2005,161 @@ static int sdhci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
return
0
;
return
0
;
}
}
static
int
sdhci_execute_tuning
(
struct
mmc_host
*
mmc
,
u32
opcode
)
static
void
sdhci_start_tuning
(
struct
sdhci_host
*
host
)
{
{
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
u16
ctrl
;
u16
ctrl
;
int
tuning_loop_counter
=
MAX_TUNING_LOOP
;
int
err
=
0
;
ctrl
=
sdhci_readw
(
host
,
SDHCI_HOST_CONTROL2
);
ctrl
|=
SDHCI_CTRL_EXEC_TUNING
;
if
(
host
->
quirks2
&
SDHCI_QUIRK2_TUNING_WORK_AROUND
)
ctrl
|=
SDHCI_CTRL_TUNED_CLK
;
sdhci_writew
(
host
,
ctrl
,
SDHCI_HOST_CONTROL2
);
/*
* As per the Host Controller spec v3.00, tuning command
* generates Buffer Read Ready interrupt, so enable that.
*
* Note: The spec clearly says that when tuning sequence
* is being performed, the controller does not generate
* interrupts other than Buffer Read Ready interrupt. But
* to make sure we don't hit a controller bug, we _only_
* enable Buffer Read Ready interrupt here.
*/
sdhci_writel
(
host
,
SDHCI_INT_DATA_AVAIL
,
SDHCI_INT_ENABLE
);
sdhci_writel
(
host
,
SDHCI_INT_DATA_AVAIL
,
SDHCI_SIGNAL_ENABLE
);
}
static
void
sdhci_end_tuning
(
struct
sdhci_host
*
host
)
{
sdhci_writel
(
host
,
host
->
ier
,
SDHCI_INT_ENABLE
);
sdhci_writel
(
host
,
host
->
ier
,
SDHCI_SIGNAL_ENABLE
);
}
static
void
sdhci_reset_tuning
(
struct
sdhci_host
*
host
)
{
u16
ctrl
;
ctrl
=
sdhci_readw
(
host
,
SDHCI_HOST_CONTROL2
);
ctrl
&=
~
SDHCI_CTRL_TUNED_CLK
;
ctrl
&=
~
SDHCI_CTRL_EXEC_TUNING
;
sdhci_writew
(
host
,
ctrl
,
SDHCI_HOST_CONTROL2
);
}
static
void
sdhci_abort_tuning
(
struct
sdhci_host
*
host
,
u32
opcode
)
{
sdhci_reset_tuning
(
host
);
sdhci_do_reset
(
host
,
SDHCI_RESET_CMD
);
sdhci_do_reset
(
host
,
SDHCI_RESET_DATA
);
sdhci_end_tuning
(
host
);
mmc_abort_tuning
(
host
->
mmc
,
opcode
);
}
/*
* We use sdhci_send_tuning() because mmc_send_tuning() is not a good fit. SDHCI
* tuning command does not have a data payload (or rather the hardware does it
* automatically) so mmc_send_tuning() will return -EIO. Also the tuning command
* interrupt setup is different to other commands and there is no timeout
* interrupt so special handling is needed.
*/
static
void
sdhci_send_tuning
(
struct
sdhci_host
*
host
,
u32
opcode
)
{
struct
mmc_host
*
mmc
=
host
->
mmc
;
struct
mmc_command
cmd
=
{};
struct
mmc_request
mrq
=
{};
unsigned
long
flags
;
unsigned
long
flags
;
unsigned
int
tuning_count
=
0
;
u32
b
=
host
->
sdma_boundary
;
bool
hs400_tuning
;
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
cmd
.
opcode
=
opcode
;
cmd
.
flags
=
MMC_RSP_R1
|
MMC_CMD_ADTC
;
cmd
.
mrq
=
&
mrq
;
mrq
.
cmd
=
&
cmd
;
/*
* In response to CMD19, the card sends 64 bytes of tuning
* block to the Host Controller. So we set the block size
* to 64 here.
*/
if
(
cmd
.
opcode
==
MMC_SEND_TUNING_BLOCK_HS200
&&
mmc
->
ios
.
bus_width
==
MMC_BUS_WIDTH_8
)
sdhci_writew
(
host
,
SDHCI_MAKE_BLKSZ
(
b
,
128
),
SDHCI_BLOCK_SIZE
);
else
sdhci_writew
(
host
,
SDHCI_MAKE_BLKSZ
(
b
,
64
),
SDHCI_BLOCK_SIZE
);
/*
* The tuning block is sent by the card to the host controller.
* So we set the TRNS_READ bit in the Transfer Mode register.
* This also takes care of setting DMA Enable and Multi Block
* Select in the same register to 0.
*/
sdhci_writew
(
host
,
SDHCI_TRNS_READ
,
SDHCI_TRANSFER_MODE
);
sdhci_send_command
(
host
,
&
cmd
);
host
->
cmd
=
NULL
;
sdhci_del_timer
(
host
,
&
mrq
);
host
->
tuning_done
=
0
;
mmiowb
();
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
/* Wait for Buffer Read Ready interrupt */
wait_event_timeout
(
host
->
buf_ready_int
,
(
host
->
tuning_done
==
1
),
msecs_to_jiffies
(
50
));
}
static
void
__sdhci_execute_tuning
(
struct
sdhci_host
*
host
,
u32
opcode
)
{
int
i
;
/*
* Issue opcode repeatedly till Execute Tuning is set to 0 or the number
* of loops reaches 40 times.
*/
for
(
i
=
0
;
i
<
MAX_TUNING_LOOP
;
i
++
)
{
u16
ctrl
;
sdhci_send_tuning
(
host
,
opcode
);
if
(
!
host
->
tuning_done
)
{
pr_info
(
"%s: Tuning timeout, falling back to fixed sampling clock
\n
"
,
mmc_hostname
(
host
->
mmc
));
sdhci_abort_tuning
(
host
,
opcode
);
return
;
}
ctrl
=
sdhci_readw
(
host
,
SDHCI_HOST_CONTROL2
);
if
(
!
(
ctrl
&
SDHCI_CTRL_EXEC_TUNING
))
{
if
(
ctrl
&
SDHCI_CTRL_TUNED_CLK
)
return
;
/* Success! */
break
;
}
/* Spec does not require a delay between tuning cycles */
if
(
host
->
tuning_delay
>
0
)
mdelay
(
host
->
tuning_delay
);
}
pr_info
(
"%s: Tuning failed, falling back to fixed sampling clock
\n
"
,
mmc_hostname
(
host
->
mmc
));
sdhci_reset_tuning
(
host
);
}
int
sdhci_execute_tuning
(
struct
mmc_host
*
mmc
,
u32
opcode
)
{
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
int
err
=
0
;
unsigned
int
tuning_count
=
0
;
bool
hs400_tuning
;
hs400_tuning
=
host
->
flags
&
SDHCI_HS400_TUNING
;
hs400_tuning
=
host
->
flags
&
SDHCI_HS400_TUNING
;
host
->
flags
&=
~
SDHCI_HS400_TUNING
;
if
(
host
->
tuning_mode
==
SDHCI_TUNING_MODE_1
)
if
(
host
->
tuning_mode
==
SDHCI_TUNING_MODE_1
)
tuning_count
=
host
->
tuning_count
;
tuning_count
=
host
->
tuning_count
;
...
@@ -2000,7 +2175,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
...
@@ -2000,7 +2175,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
/* HS400 tuning is done in HS200 mode */
/* HS400 tuning is done in HS200 mode */
case
MMC_TIMING_MMC_HS400
:
case
MMC_TIMING_MMC_HS400
:
err
=
-
EINVAL
;
err
=
-
EINVAL
;
goto
out
_unlock
;
goto
out
;
case
MMC_TIMING_MMC_HS200
:
case
MMC_TIMING_MMC_HS200
:
/*
/*
...
@@ -2021,162 +2196,30 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
...
@@ -2021,162 +2196,30 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
/* FALLTHROUGH */
/* FALLTHROUGH */
default:
default:
goto
out
_unlock
;
goto
out
;
}
}
if
(
host
->
ops
->
platform_execute_tuning
)
{
if
(
host
->
ops
->
platform_execute_tuning
)
{
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
err
=
host
->
ops
->
platform_execute_tuning
(
host
,
opcode
);
err
=
host
->
ops
->
platform_execute_tuning
(
host
,
opcode
);
return
err
;
goto
out
;
}
}
ctrl
=
sdhci_readw
(
host
,
SDHCI_HOST_CONTROL2
);
host
->
mmc
->
retune_period
=
tuning_count
;
ctrl
|=
SDHCI_CTRL_EXEC_TUNING
;
if
(
host
->
quirks2
&
SDHCI_QUIRK2_TUNING_WORK_AROUND
)
ctrl
|=
SDHCI_CTRL_TUNED_CLK
;
sdhci_writew
(
host
,
ctrl
,
SDHCI_HOST_CONTROL2
);
/*
if
(
host
->
tuning_delay
<
0
)
* As per the Host Controller spec v3.00, tuning command
host
->
tuning_delay
=
opcode
==
MMC_SEND_TUNING_BLOCK
;
* generates Buffer Read Ready interrupt, so enable that.
*
* Note: The spec clearly says that when tuning sequence
* is being performed, the controller does not generate
* interrupts other than Buffer Read Ready interrupt. But
* to make sure we don't hit a controller bug, we _only_
* enable Buffer Read Ready interrupt here.
*/
sdhci_writel
(
host
,
SDHCI_INT_DATA_AVAIL
,
SDHCI_INT_ENABLE
);
sdhci_writel
(
host
,
SDHCI_INT_DATA_AVAIL
,
SDHCI_SIGNAL_ENABLE
);
/*
* Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
* of loops reaches 40 times.
*/
do
{
struct
mmc_command
cmd
=
{
0
};
struct
mmc_request
mrq
=
{
NULL
};
cmd
.
opcode
=
opcode
;
cmd
.
arg
=
0
;
cmd
.
flags
=
MMC_RSP_R1
|
MMC_CMD_ADTC
;
cmd
.
retries
=
0
;
cmd
.
data
=
NULL
;
cmd
.
mrq
=
&
mrq
;
cmd
.
error
=
0
;
if
(
tuning_loop_counter
--
==
0
)
break
;
mrq
.
cmd
=
&
cmd
;
/*
* In response to CMD19, the card sends 64 bytes of tuning
* block to the Host Controller. So we set the block size
* to 64 here.
*/
if
(
cmd
.
opcode
==
MMC_SEND_TUNING_BLOCK_HS200
)
{
if
(
mmc
->
ios
.
bus_width
==
MMC_BUS_WIDTH_8
)
sdhci_writew
(
host
,
SDHCI_MAKE_BLKSZ
(
7
,
128
),
SDHCI_BLOCK_SIZE
);
else
if
(
mmc
->
ios
.
bus_width
==
MMC_BUS_WIDTH_4
)
sdhci_writew
(
host
,
SDHCI_MAKE_BLKSZ
(
7
,
64
),
SDHCI_BLOCK_SIZE
);
}
else
{
sdhci_writew
(
host
,
SDHCI_MAKE_BLKSZ
(
7
,
64
),
SDHCI_BLOCK_SIZE
);
}
/*
* The tuning block is sent by the card to the host controller.
* So we set the TRNS_READ bit in the Transfer Mode register.
* This also takes care of setting DMA Enable and Multi Block
* Select in the same register to 0.
*/
sdhci_writew
(
host
,
SDHCI_TRNS_READ
,
SDHCI_TRANSFER_MODE
);
sdhci_send_command
(
host
,
&
cmd
);
host
->
cmd
=
NULL
;
sdhci_del_timer
(
host
,
&
mrq
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
/* Wait for Buffer Read Ready interrupt */
wait_event_timeout
(
host
->
buf_ready_int
,
(
host
->
tuning_done
==
1
),
msecs_to_jiffies
(
50
));
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
if
(
!
host
->
tuning_done
)
{
pr_info
(
DRIVER_NAME
": Timeout waiting for Buffer Read Ready interrupt during tuning procedure, falling back to fixed sampling clock
\n
"
);
sdhci_do_reset
(
host
,
SDHCI_RESET_CMD
);
sdhci_do_reset
(
host
,
SDHCI_RESET_DATA
);
ctrl
=
sdhci_readw
(
host
,
SDHCI_HOST_CONTROL2
);
sdhci_start_tuning
(
host
);
ctrl
&=
~
SDHCI_CTRL_TUNED_CLK
;
ctrl
&=
~
SDHCI_CTRL_EXEC_TUNING
;
sdhci_writew
(
host
,
ctrl
,
SDHCI_HOST_CONTROL2
);
err
=
-
EIO
;
__sdhci_execute_tuning
(
host
,
opcode
);
goto
out
;
}
host
->
tuning_done
=
0
;
ctrl
=
sdhci_readw
(
host
,
SDHCI_HOST_CONTROL2
);
/* eMMC spec does not require a delay between tuning cycles */
if
(
opcode
==
MMC_SEND_TUNING_BLOCK
)
mdelay
(
1
);
}
while
(
ctrl
&
SDHCI_CTRL_EXEC_TUNING
);
/*
* The Host Driver has exhausted the maximum number of loops allowed,
* so use fixed sampling frequency.
*/
if
(
tuning_loop_counter
<
0
)
{
ctrl
&=
~
SDHCI_CTRL_TUNED_CLK
;
sdhci_writew
(
host
,
ctrl
,
SDHCI_HOST_CONTROL2
);
}
if
(
!
(
ctrl
&
SDHCI_CTRL_TUNED_CLK
))
{
pr_info
(
DRIVER_NAME
": Tuning procedure failed, falling back to fixed sampling clock
\n
"
);
err
=
-
EIO
;
}
sdhci_end_tuning
(
host
);
out:
out:
if
(
tuning_count
)
{
host
->
flags
&=
~
SDHCI_HS400_TUNING
;
/*
* In case tuning fails, host controllers which support
* re-tuning can try tuning again at a later time, when the
* re-tuning timer expires. So for these controllers, we
* return 0. Since there might be other controllers who do not
* have this capability, we return error for them.
*/
err
=
0
;
}
host
->
mmc
->
retune_period
=
err
?
0
:
tuning_count
;
sdhci_writel
(
host
,
host
->
ier
,
SDHCI_INT_ENABLE
);
sdhci_writel
(
host
,
host
->
ier
,
SDHCI_SIGNAL_ENABLE
);
out_unlock:
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
return
err
;
return
err
;
}
}
EXPORT_SYMBOL_GPL
(
sdhci_execute_tuning
);
static
int
sdhci_select_drive_strength
(
struct
mmc_card
*
card
,
unsigned
int
max_dtr
,
int
host_drv
,
int
card_drv
,
int
*
drv_type
)
{
struct
sdhci_host
*
host
=
mmc_priv
(
card
->
host
);
if
(
!
host
->
ops
->
select_drive_strength
)
return
0
;
return
host
->
ops
->
select_drive_strength
(
host
,
card
,
max_dtr
,
host_drv
,
card_drv
,
drv_type
);
}
static
void
sdhci_enable_preset_value
(
struct
sdhci_host
*
host
,
bool
enable
)
static
void
sdhci_enable_preset_value
(
struct
sdhci_host
*
host
,
bool
enable
)
{
{
...
@@ -2215,14 +2258,12 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
...
@@ -2215,14 +2258,12 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
if
(
data
->
host_cookie
!=
COOKIE_UNMAPPED
)
if
(
data
->
host_cookie
!=
COOKIE_UNMAPPED
)
dma_unmap_sg
(
mmc_dev
(
host
->
mmc
),
data
->
sg
,
data
->
sg_len
,
dma_unmap_sg
(
mmc_dev
(
host
->
mmc
),
data
->
sg
,
data
->
sg_len
,
data
->
flags
&
MMC_DATA_WRITE
?
mmc_get_dma_dir
(
data
));
DMA_TO_DEVICE
:
DMA_FROM_DEVICE
);
data
->
host_cookie
=
COOKIE_UNMAPPED
;
data
->
host_cookie
=
COOKIE_UNMAPPED
;
}
}
static
void
sdhci_pre_req
(
struct
mmc_host
*
mmc
,
struct
mmc_request
*
mrq
,
static
void
sdhci_pre_req
(
struct
mmc_host
*
mmc
,
struct
mmc_request
*
mrq
)
bool
is_first_req
)
{
{
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
...
@@ -2292,7 +2333,6 @@ static const struct mmc_host_ops sdhci_ops = {
...
@@ -2292,7 +2333,6 @@ static const struct mmc_host_ops sdhci_ops = {
.
start_signal_voltage_switch
=
sdhci_start_signal_voltage_switch
,
.
start_signal_voltage_switch
=
sdhci_start_signal_voltage_switch
,
.
prepare_hs400_tuning
=
sdhci_prepare_hs400_tuning
,
.
prepare_hs400_tuning
=
sdhci_prepare_hs400_tuning
,
.
execute_tuning
=
sdhci_execute_tuning
,
.
execute_tuning
=
sdhci_execute_tuning
,
.
select_drive_strength
=
sdhci_select_drive_strength
,
.
card_event
=
sdhci_card_event
,
.
card_event
=
sdhci_card_event
,
.
card_busy
=
sdhci_card_busy
,
.
card_busy
=
sdhci_card_busy
,
};
};
...
@@ -2334,8 +2374,7 @@ static bool sdhci_request_done(struct sdhci_host *host)
...
@@ -2334,8 +2374,7 @@ static bool sdhci_request_done(struct sdhci_host *host)
if
(
data
&&
data
->
host_cookie
==
COOKIE_MAPPED
)
{
if
(
data
&&
data
->
host_cookie
==
COOKIE_MAPPED
)
{
dma_unmap_sg
(
mmc_dev
(
host
->
mmc
),
data
->
sg
,
data
->
sg_len
,
dma_unmap_sg
(
mmc_dev
(
host
->
mmc
),
data
->
sg
,
data
->
sg_len
,
(
data
->
flags
&
MMC_DATA_READ
)
?
mmc_get_dma_dir
(
data
));
DMA_FROM_DEVICE
:
DMA_TO_DEVICE
);
data
->
host_cookie
=
COOKIE_UNMAPPED
;
data
->
host_cookie
=
COOKIE_UNMAPPED
;
}
}
}
}
...
@@ -2497,10 +2536,8 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
...
@@ -2497,10 +2536,8 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
sdhci_finish_command
(
host
);
sdhci_finish_command
(
host
);
}
}
#ifdef CONFIG_MMC_DEBUG
static
void
sdhci_adma_show_error
(
struct
sdhci_host
*
host
)
static
void
sdhci_adma_show_error
(
struct
sdhci_host
*
host
)
{
{
const
char
*
name
=
mmc_hostname
(
host
->
mmc
);
void
*
desc
=
host
->
adma_table
;
void
*
desc
=
host
->
adma_table
;
sdhci_dumpregs
(
host
);
sdhci_dumpregs
(
host
);
...
@@ -2509,14 +2546,14 @@ static void sdhci_adma_show_error(struct sdhci_host *host)
...
@@ -2509,14 +2546,14 @@ static void sdhci_adma_show_error(struct sdhci_host *host)
struct
sdhci_adma2_64_desc
*
dma_desc
=
desc
;
struct
sdhci_adma2_64_desc
*
dma_desc
=
desc
;
if
(
host
->
flags
&
SDHCI_USE_64_BIT_DMA
)
if
(
host
->
flags
&
SDHCI_USE_64_BIT_DMA
)
DBG
(
"%
s: %
p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x
\n
"
,
DBG
(
"%p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x
\n
"
,
name
,
desc
,
le32_to_cpu
(
dma_desc
->
addr_hi
),
desc
,
le32_to_cpu
(
dma_desc
->
addr_hi
),
le32_to_cpu
(
dma_desc
->
addr_lo
),
le32_to_cpu
(
dma_desc
->
addr_lo
),
le16_to_cpu
(
dma_desc
->
len
),
le16_to_cpu
(
dma_desc
->
len
),
le16_to_cpu
(
dma_desc
->
cmd
));
le16_to_cpu
(
dma_desc
->
cmd
));
else
else
DBG
(
"%
s: %
p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x
\n
"
,
DBG
(
"%p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x
\n
"
,
name
,
desc
,
le32_to_cpu
(
dma_desc
->
addr_lo
),
desc
,
le32_to_cpu
(
dma_desc
->
addr_lo
),
le16_to_cpu
(
dma_desc
->
len
),
le16_to_cpu
(
dma_desc
->
len
),
le16_to_cpu
(
dma_desc
->
cmd
));
le16_to_cpu
(
dma_desc
->
cmd
));
...
@@ -2526,9 +2563,6 @@ static void sdhci_adma_show_error(struct sdhci_host *host)
...
@@ -2526,9 +2563,6 @@ static void sdhci_adma_show_error(struct sdhci_host *host)
break
;
break
;
}
}
}
}
#else
static
void
sdhci_adma_show_error
(
struct
sdhci_host
*
host
)
{
}
#endif
static
void
sdhci_data_irq
(
struct
sdhci_host
*
host
,
u32
intmask
)
static
void
sdhci_data_irq
(
struct
sdhci_host
*
host
,
u32
intmask
)
{
{
...
@@ -2632,10 +2666,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
...
@@ -2632,10 +2666,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
~
(
SDHCI_DEFAULT_BOUNDARY_SIZE
-
1
))
+
~
(
SDHCI_DEFAULT_BOUNDARY_SIZE
-
1
))
+
SDHCI_DEFAULT_BOUNDARY_SIZE
;
SDHCI_DEFAULT_BOUNDARY_SIZE
;
host
->
data
->
bytes_xfered
=
dmanow
-
dmastart
;
host
->
data
->
bytes_xfered
=
dmanow
-
dmastart
;
DBG
(
"%s: DMA base 0x%08x, transferred 0x%06x bytes,"
DBG
(
"DMA base 0x%08x, transferred 0x%06x bytes, next 0x%08x
\n
"
,
" next 0x%08x
\n
"
,
dmastart
,
host
->
data
->
bytes_xfered
,
dmanow
);
mmc_hostname
(
host
->
mmc
),
dmastart
,
host
->
data
->
bytes_xfered
,
dmanow
);
sdhci_writel
(
host
,
dmanow
,
SDHCI_DMA_ADDRESS
);
sdhci_writel
(
host
,
dmanow
,
SDHCI_DMA_ADDRESS
);
}
}
...
@@ -2675,14 +2707,19 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
...
@@ -2675,14 +2707,19 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
}
}
do
{
do
{
DBG
(
"IRQ status 0x%08x
\n
"
,
intmask
);
if
(
host
->
ops
->
irq
)
{
intmask
=
host
->
ops
->
irq
(
host
,
intmask
);
if
(
!
intmask
)
goto
cont
;
}
/* Clear selected interrupts. */
/* Clear selected interrupts. */
mask
=
intmask
&
(
SDHCI_INT_CMD_MASK
|
SDHCI_INT_DATA_MASK
|
mask
=
intmask
&
(
SDHCI_INT_CMD_MASK
|
SDHCI_INT_DATA_MASK
|
SDHCI_INT_BUS_POWER
);
SDHCI_INT_BUS_POWER
);
sdhci_writel
(
host
,
mask
,
SDHCI_INT_STATUS
);
sdhci_writel
(
host
,
mask
,
SDHCI_INT_STATUS
);
DBG
(
"*** %s got interrupt: 0x%08x
\n
"
,
mmc_hostname
(
host
->
mmc
),
intmask
);
if
(
intmask
&
(
SDHCI_INT_CARD_INSERT
|
SDHCI_INT_CARD_REMOVE
))
{
if
(
intmask
&
(
SDHCI_INT_CARD_INSERT
|
SDHCI_INT_CARD_REMOVE
))
{
u32
present
=
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
)
&
u32
present
=
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
)
&
// Elphel
// Elphel
...
@@ -2728,7 +2765,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
...
@@ -2728,7 +2765,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
if
(
intmask
&
SDHCI_INT_RETUNE
)
if
(
intmask
&
SDHCI_INT_RETUNE
)
mmc_retune_needed
(
host
->
mmc
);
mmc_retune_needed
(
host
->
mmc
);
if
(
intmask
&
SDHCI_INT_CARD_INT
)
{
if
((
intmask
&
SDHCI_INT_CARD_INT
)
&&
(
host
->
ier
&
SDHCI_INT_CARD_INT
))
{
sdhci_enable_sdio_irq_nolock
(
host
,
false
);
sdhci_enable_sdio_irq_nolock
(
host
,
false
);
host
->
thread_isr
|=
SDHCI_INT_CARD_INT
;
host
->
thread_isr
|=
SDHCI_INT_CARD_INT
;
result
=
IRQ_WAKE_THREAD
;
result
=
IRQ_WAKE_THREAD
;
...
@@ -2743,7 +2781,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
...
@@ -2743,7 +2781,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
unexpected
|=
intmask
;
unexpected
|=
intmask
;
sdhci_writel
(
host
,
intmask
,
SDHCI_INT_STATUS
);
sdhci_writel
(
host
,
intmask
,
SDHCI_INT_STATUS
);
}
}
cont:
if
(
result
==
IRQ_NONE
)
if
(
result
==
IRQ_NONE
)
result
=
IRQ_HANDLED
;
result
=
IRQ_HANDLED
;
...
@@ -2842,8 +2880,6 @@ int sdhci_suspend_host(struct sdhci_host *host)
...
@@ -2842,8 +2880,6 @@ int sdhci_suspend_host(struct sdhci_host *host)
sdhci_disable_card_detection
(
host
);
sdhci_disable_card_detection
(
host
);
mmc_retune_timer_stop
(
host
->
mmc
);
mmc_retune_timer_stop
(
host
->
mmc
);
if
(
host
->
tuning_mode
!=
SDHCI_TUNING_MODE_3
)
mmc_retune_needed
(
host
->
mmc
);
if
(
!
device_may_wakeup
(
mmc_dev
(
host
->
mmc
)))
{
if
(
!
device_may_wakeup
(
mmc_dev
(
host
->
mmc
)))
{
host
->
ier
=
0
;
host
->
ier
=
0
;
...
@@ -2904,8 +2940,6 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
...
@@ -2904,8 +2940,6 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
unsigned
long
flags
;
unsigned
long
flags
;
mmc_retune_timer_stop
(
host
->
mmc
);
mmc_retune_timer_stop
(
host
->
mmc
);
if
(
host
->
tuning_mode
!=
SDHCI_TUNING_MODE_3
)
mmc_retune_needed
(
host
->
mmc
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
host
->
ier
&=
SDHCI_INT_CARD_INT
;
host
->
ier
&=
SDHCI_INT_CARD_INT
;
...
@@ -2936,22 +2970,25 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
...
@@ -2936,22 +2970,25 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
sdhci_init
(
host
,
0
);
sdhci_init
(
host
,
0
);
/* Force clock and power re-program */
if
(
mmc
->
ios
.
power_mode
!=
MMC_POWER_UNDEFINED
&&
host
->
pwr
=
0
;
mmc
->
ios
.
power_mode
!=
MMC_POWER_OFF
)
{
host
->
clock
=
0
;
/* Force clock and power re-program */
mmc
->
ops
->
start_signal_voltage_switch
(
mmc
,
&
mmc
->
ios
);
host
->
pwr
=
0
;
mmc
->
ops
->
set_ios
(
mmc
,
&
mmc
->
ios
);
host
->
clock
=
0
;
mmc
->
ops
->
start_signal_voltage_switch
(
mmc
,
&
mmc
->
ios
);
mmc
->
ops
->
set_ios
(
mmc
,
&
mmc
->
ios
);
if
((
host_flags
&
SDHCI_PV_ENABLED
)
&&
if
((
host_flags
&
SDHCI_PV_ENABLED
)
&&
!
(
host
->
quirks2
&
SDHCI_QUIRK2_PRESET_VALUE_BROKEN
))
{
!
(
host
->
quirks2
&
SDHCI_QUIRK2_PRESET_VALUE_BROKEN
))
{
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
sdhci_enable_preset_value
(
host
,
true
);
sdhci_enable_preset_value
(
host
,
true
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
}
}
if
((
mmc
->
caps2
&
MMC_CAP2_HS400_ES
)
&&
if
((
mmc
->
caps2
&
MMC_CAP2_HS400_ES
)
&&
mmc
->
ops
->
hs400_enhanced_strobe
)
mmc
->
ops
->
hs400_enhanced_strobe
)
mmc
->
ops
->
hs400_enhanced_strobe
(
mmc
,
&
mmc
->
ios
);
mmc
->
ops
->
hs400_enhanced_strobe
(
mmc
,
&
mmc
->
ios
);
}
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
...
@@ -2972,6 +3009,119 @@ EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host);
...
@@ -2972,6 +3009,119 @@ EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host);
#endif
/* CONFIG_PM */
#endif
/* CONFIG_PM */
/*****************************************************************************\
* *
* Command Queue Engine (CQE) helpers *
* *
\*****************************************************************************/
void
sdhci_cqe_enable
(
struct
mmc_host
*
mmc
)
{
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
unsigned
long
flags
;
u8
ctrl
;
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
ctrl
=
sdhci_readb
(
host
,
SDHCI_HOST_CONTROL
);
ctrl
&=
~
SDHCI_CTRL_DMA_MASK
;
if
(
host
->
flags
&
SDHCI_USE_64_BIT_DMA
)
ctrl
|=
SDHCI_CTRL_ADMA64
;
else
ctrl
|=
SDHCI_CTRL_ADMA32
;
sdhci_writeb
(
host
,
ctrl
,
SDHCI_HOST_CONTROL
);
sdhci_writew
(
host
,
SDHCI_MAKE_BLKSZ
(
host
->
sdma_boundary
,
512
),
SDHCI_BLOCK_SIZE
);
/* Set maximum timeout */
sdhci_writeb
(
host
,
0xE
,
SDHCI_TIMEOUT_CONTROL
);
host
->
ier
=
host
->
cqe_ier
;
sdhci_writel
(
host
,
host
->
ier
,
SDHCI_INT_ENABLE
);
sdhci_writel
(
host
,
host
->
ier
,
SDHCI_SIGNAL_ENABLE
);
host
->
cqe_on
=
true
;
pr_debug
(
"%s: sdhci: CQE on, IRQ mask %#x, IRQ status %#x
\n
"
,
mmc_hostname
(
mmc
),
host
->
ier
,
sdhci_readl
(
host
,
SDHCI_INT_STATUS
));
mmiowb
();
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
}
EXPORT_SYMBOL_GPL
(
sdhci_cqe_enable
);
void
sdhci_cqe_disable
(
struct
mmc_host
*
mmc
,
bool
recovery
)
{
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
unsigned
long
flags
;
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
sdhci_set_default_irqs
(
host
);
host
->
cqe_on
=
false
;
if
(
recovery
)
{
sdhci_do_reset
(
host
,
SDHCI_RESET_CMD
);
sdhci_do_reset
(
host
,
SDHCI_RESET_DATA
);
}
pr_debug
(
"%s: sdhci: CQE off, IRQ mask %#x, IRQ status %#x
\n
"
,
mmc_hostname
(
mmc
),
host
->
ier
,
sdhci_readl
(
host
,
SDHCI_INT_STATUS
));
mmiowb
();
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
}
EXPORT_SYMBOL_GPL
(
sdhci_cqe_disable
);
bool
sdhci_cqe_irq
(
struct
sdhci_host
*
host
,
u32
intmask
,
int
*
cmd_error
,
int
*
data_error
)
{
u32
mask
;
if
(
!
host
->
cqe_on
)
return
false
;
if
(
intmask
&
(
SDHCI_INT_INDEX
|
SDHCI_INT_END_BIT
|
SDHCI_INT_CRC
))
*
cmd_error
=
-
EILSEQ
;
else
if
(
intmask
&
SDHCI_INT_TIMEOUT
)
*
cmd_error
=
-
ETIMEDOUT
;
else
*
cmd_error
=
0
;
if
(
intmask
&
(
SDHCI_INT_DATA_END_BIT
|
SDHCI_INT_DATA_CRC
))
*
data_error
=
-
EILSEQ
;
else
if
(
intmask
&
SDHCI_INT_DATA_TIMEOUT
)
*
data_error
=
-
ETIMEDOUT
;
else
if
(
intmask
&
SDHCI_INT_ADMA_ERROR
)
*
data_error
=
-
EIO
;
else
*
data_error
=
0
;
/* Clear selected interrupts. */
mask
=
intmask
&
host
->
cqe_ier
;
sdhci_writel
(
host
,
mask
,
SDHCI_INT_STATUS
);
if
(
intmask
&
SDHCI_INT_BUS_POWER
)
pr_err
(
"%s: Card is consuming too much power!
\n
"
,
mmc_hostname
(
host
->
mmc
));
intmask
&=
~
(
host
->
cqe_ier
|
SDHCI_INT_ERROR
);
if
(
intmask
)
{
sdhci_writel
(
host
,
intmask
,
SDHCI_INT_STATUS
);
pr_err
(
"%s: CQE: Unexpected interrupt 0x%08x.
\n
"
,
mmc_hostname
(
host
->
mmc
),
intmask
);
sdhci_dumpregs
(
host
);
}
return
true
;
}
EXPORT_SYMBOL_GPL
(
sdhci_cqe_irq
);
/*****************************************************************************\
/*****************************************************************************\
* *
* *
* Device allocation/registration *
* Device allocation/registration *
...
@@ -2997,6 +3147,13 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
...
@@ -2997,6 +3147,13 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
host
->
flags
=
SDHCI_SIGNALING_330
;
host
->
flags
=
SDHCI_SIGNALING_330
;
host
->
cqe_ier
=
SDHCI_CQE_INT_MASK
;
host
->
cqe_err_ier
=
SDHCI_CQE_INT_ERR_MASK
;
host
->
tuning_delay
=
-
1
;
host
->
sdma_boundary
=
SDHCI_DEFAULT_BOUNDARY_ARG
;
return
host
;
return
host
;
}
}
...
@@ -3035,6 +3192,8 @@ static int sdhci_set_dma_mask(struct sdhci_host *host)
...
@@ -3035,6 +3192,8 @@ static int sdhci_set_dma_mask(struct sdhci_host *host)
void
__sdhci_read_caps
(
struct
sdhci_host
*
host
,
u16
*
ver
,
u32
*
caps
,
u32
*
caps1
)
void
__sdhci_read_caps
(
struct
sdhci_host
*
host
,
u16
*
ver
,
u32
*
caps
,
u32
*
caps1
)
{
{
u16
v
;
u16
v
;
u64
dt_caps_mask
=
0
;
u64
dt_caps
=
0
;
if
(
host
->
read_caps
)
if
(
host
->
read_caps
)
return
;
return
;
...
@@ -3049,18 +3208,35 @@ void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps, u32 *caps1)
...
@@ -3049,18 +3208,35 @@ void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps, u32 *caps1)
sdhci_do_reset
(
host
,
SDHCI_RESET_ALL
);
sdhci_do_reset
(
host
,
SDHCI_RESET_ALL
);
of_property_read_u64
(
mmc_dev
(
host
->
mmc
)
->
of_node
,
"sdhci-caps-mask"
,
&
dt_caps_mask
);
of_property_read_u64
(
mmc_dev
(
host
->
mmc
)
->
of_node
,
"sdhci-caps"
,
&
dt_caps
);
v
=
ver
?
*
ver
:
sdhci_readw
(
host
,
SDHCI_HOST_VERSION
);
v
=
ver
?
*
ver
:
sdhci_readw
(
host
,
SDHCI_HOST_VERSION
);
host
->
version
=
(
v
&
SDHCI_SPEC_VER_MASK
)
>>
SDHCI_SPEC_VER_SHIFT
;
host
->
version
=
(
v
&
SDHCI_SPEC_VER_MASK
)
>>
SDHCI_SPEC_VER_SHIFT
;
if
(
host
->
quirks
&
SDHCI_QUIRK_MISSING_CAPS
)
if
(
host
->
quirks
&
SDHCI_QUIRK_MISSING_CAPS
)
return
;
return
;
host
->
caps
=
caps
?
*
caps
:
sdhci_readl
(
host
,
SDHCI_CAPABILITIES
);
if
(
caps
)
{
host
->
caps
=
*
caps
;
}
else
{
host
->
caps
=
sdhci_readl
(
host
,
SDHCI_CAPABILITIES
);
host
->
caps
&=
~
lower_32_bits
(
dt_caps_mask
);
host
->
caps
|=
lower_32_bits
(
dt_caps
);
}
if
(
host
->
version
<
SDHCI_SPEC_300
)
if
(
host
->
version
<
SDHCI_SPEC_300
)
return
;
return
;
host
->
caps1
=
caps1
?
*
caps1
:
sdhci_readl
(
host
,
SDHCI_CAPABILITIES_1
);
if
(
caps1
)
{
host
->
caps1
=
*
caps1
;
}
else
{
host
->
caps1
=
sdhci_readl
(
host
,
SDHCI_CAPABILITIES_1
);
host
->
caps1
&=
~
upper_32_bits
(
dt_caps_mask
);
host
->
caps1
|=
upper_32_bits
(
dt_caps
);
}
}
}
EXPORT_SYMBOL_GPL
(
__sdhci_read_caps
);
EXPORT_SYMBOL_GPL
(
__sdhci_read_caps
);
...
@@ -3089,6 +3265,13 @@ int sdhci_setup_host(struct sdhci_host *host)
...
@@ -3089,6 +3265,13 @@ int sdhci_setup_host(struct sdhci_host *host)
if
(
ret
==
-
EPROBE_DEFER
)
if
(
ret
==
-
EPROBE_DEFER
)
return
ret
;
return
ret
;
DBG
(
"Version: 0x%08x | Present: 0x%08x
\n
"
,
sdhci_readw
(
host
,
SDHCI_HOST_VERSION
),
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
));
DBG
(
"Caps: 0x%08x | Caps_1: 0x%08x
\n
"
,
sdhci_readl
(
host
,
SDHCI_CAPABILITIES
),
sdhci_readl
(
host
,
SDHCI_CAPABILITIES_1
));
sdhci_read_caps
(
host
);
sdhci_read_caps
(
host
);
override_timeout_clk
=
host
->
timeout_clk
;
override_timeout_clk
=
host
->
timeout_clk
;
...
@@ -3260,20 +3443,22 @@ int sdhci_setup_host(struct sdhci_host *host)
...
@@ -3260,20 +3443,22 @@ int sdhci_setup_host(struct sdhci_host *host)
if
(
!
(
host
->
quirks
&
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
))
{
if
(
!
(
host
->
quirks
&
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
))
{
host
->
timeout_clk
=
(
host
->
caps
&
SDHCI_TIMEOUT_CLK_MASK
)
>>
host
->
timeout_clk
=
(
host
->
caps
&
SDHCI_TIMEOUT_CLK_MASK
)
>>
SDHCI_TIMEOUT_CLK_SHIFT
;
SDHCI_TIMEOUT_CLK_SHIFT
;
if
(
host
->
caps
&
SDHCI_TIMEOUT_CLK_UNIT
)
host
->
timeout_clk
*=
1000
;
if
(
host
->
timeout_clk
==
0
)
{
if
(
host
->
timeout_clk
==
0
)
{
if
(
host
->
ops
->
get_timeout_clock
)
{
if
(
!
host
->
ops
->
get_timeout_clock
)
{
host
->
timeout_clk
=
host
->
ops
->
get_timeout_clock
(
host
);
}
else
{
pr_err
(
"%s: Hardware doesn't specify timeout clock frequency.
\n
"
,
pr_err
(
"%s: Hardware doesn't specify timeout clock frequency.
\n
"
,
mmc_hostname
(
mmc
));
mmc_hostname
(
mmc
));
ret
=
-
ENODEV
;
ret
=
-
ENODEV
;
goto
undma
;
goto
undma
;
}
}
}
if
(
host
->
caps
&
SDHCI_TIMEOUT_CLK_UNIT
)
host
->
timeout_clk
=
host
->
timeout_clk
*=
1000
;
DIV_ROUND_UP
(
host
->
ops
->
get_timeout_clock
(
host
),
1000
);
}
if
(
override_timeout_clk
)
if
(
override_timeout_clk
)
host
->
timeout_clk
=
override_timeout_clk
;
host
->
timeout_clk
=
override_timeout_clk
;
...
@@ -3295,9 +3480,9 @@ int sdhci_setup_host(struct sdhci_host *host)
...
@@ -3295,9 +3480,9 @@ int sdhci_setup_host(struct sdhci_host *host)
!
(
host
->
flags
&
SDHCI_USE_SDMA
))
&&
!
(
host
->
flags
&
SDHCI_USE_SDMA
))
&&
!
(
host
->
quirks2
&
SDHCI_QUIRK2_ACMD23_BROKEN
))
{
!
(
host
->
quirks2
&
SDHCI_QUIRK2_ACMD23_BROKEN
))
{
host
->
flags
|=
SDHCI_AUTO_CMD23
;
host
->
flags
|=
SDHCI_AUTO_CMD23
;
DBG
(
"
%s: Auto-CMD23 available
\n
"
,
mmc_hostname
(
mmc
)
);
DBG
(
"
Auto-CMD23 available
\n
"
);
}
else
{
}
else
{
DBG
(
"
%s: Auto-CMD23 unavailable
\n
"
,
mmc_hostname
(
mmc
)
);
DBG
(
"
Auto-CMD23 unavailable
\n
"
);
}
}
/*
/*
...
@@ -3562,6 +3747,22 @@ undma:
...
@@ -3562,6 +3747,22 @@ undma:
}
}
EXPORT_SYMBOL_GPL
(
sdhci_setup_host
);
EXPORT_SYMBOL_GPL
(
sdhci_setup_host
);
void
sdhci_cleanup_host
(
struct
sdhci_host
*
host
)
{
struct
mmc_host
*
mmc
=
host
->
mmc
;
if
(
!
IS_ERR
(
mmc
->
supply
.
vqmmc
))
regulator_disable
(
mmc
->
supply
.
vqmmc
);
if
(
host
->
align_buffer
)
dma_free_coherent
(
mmc_dev
(
mmc
),
host
->
align_buffer_sz
+
host
->
adma_table_sz
,
host
->
align_buffer
,
host
->
align_addr
);
host
->
adma_table
=
NULL
;
host
->
align_buffer
=
NULL
;
}
EXPORT_SYMBOL_GPL
(
sdhci_cleanup_host
);
int
__sdhci_add_host
(
struct
sdhci_host
*
host
)
int
__sdhci_add_host
(
struct
sdhci_host
*
host
)
{
{
struct
mmc_host
*
mmc
=
host
->
mmc
;
struct
mmc_host
*
mmc
=
host
->
mmc
;
...
@@ -3589,10 +3790,6 @@ int __sdhci_add_host(struct sdhci_host *host)
...
@@ -3589,10 +3790,6 @@ int __sdhci_add_host(struct sdhci_host *host)
goto
untasklet
;
goto
untasklet
;
}
}
#ifdef CONFIG_MMC_DEBUG
sdhci_dumpregs
(
host
);
#endif
ret
=
sdhci_led_register
(
host
);
ret
=
sdhci_led_register
(
host
);
if
(
ret
)
{
if
(
ret
)
{
pr_err
(
"%s: Failed to register LED device: %d
\n
"
,
pr_err
(
"%s: Failed to register LED device: %d
\n
"
,
...
@@ -3626,16 +3823,6 @@ unirq:
...
@@ -3626,16 +3823,6 @@ unirq:
untasklet:
untasklet:
tasklet_kill
(
&
host
->
finish_tasklet
);
tasklet_kill
(
&
host
->
finish_tasklet
);
if
(
!
IS_ERR
(
mmc
->
supply
.
vqmmc
))
regulator_disable
(
mmc
->
supply
.
vqmmc
);
if
(
host
->
align_buffer
)
dma_free_coherent
(
mmc_dev
(
mmc
),
host
->
align_buffer_sz
+
host
->
adma_table_sz
,
host
->
align_buffer
,
host
->
align_addr
);
host
->
adma_table
=
NULL
;
host
->
align_buffer
=
NULL
;
return
ret
;
return
ret
;
}
}
EXPORT_SYMBOL_GPL
(
__sdhci_add_host
);
EXPORT_SYMBOL_GPL
(
__sdhci_add_host
);
...
@@ -3648,7 +3835,16 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3648,7 +3835,16 @@ int sdhci_add_host(struct sdhci_host *host)
if
(
ret
)
if
(
ret
)
return
ret
;
return
ret
;
return
__sdhci_add_host
(
host
);
ret
=
__sdhci_add_host
(
host
);
if
(
ret
)
goto
cleanup
;
return
0
;
cleanup:
sdhci_cleanup_host
(
host
);
return
ret
;
}
}
EXPORT_SYMBOL_GPL
(
sdhci_add_host
);
EXPORT_SYMBOL_GPL
(
sdhci_add_host
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment