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
Show 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 @@
*/
#include <linux/delay.h>
#include <linux/ktime.h>
#include <linux/highmem.h>
#include <linux/io.h>
#include <linux/module.h>
...
...
@@ -22,6 +23,7 @@
#include <linux/scatterlist.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/leds.h>
...
...
@@ -36,7 +38,10 @@
#define DRIVER_NAME "sdhci"
#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
...
...
@@ -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_dumpregs
(
struct
sdhci_host
*
host
)
void
sdhci_dumpregs
(
struct
sdhci_host
*
host
)
{
pr_err
(
DRIVER_NAME
": =========== REGISTER DUMP (%s)===========
\n
"
,
mmc_hostname
(
host
->
mmc
));
SDHCI_DUMP
(
"============ SDHCI REGISTER DUMP ===========
\n
"
);
pr_err
(
DRIVER_NAME
": Sys addr:
0x%08x | Version: 0x%08x
\n
"
,
SDHCI_DUMP
(
"Sys addr:
0x%08x | Version: 0x%08x
\n
"
,
sdhci_readl
(
host
,
SDHCI_DMA_ADDRESS
),
sdhci_readw
(
host
,
SDHCI_HOST_VERSION
));
pr_err
(
DRIVER_NAME
": Blk size:
0x%08x | Blk cnt: 0x%08x
\n
"
,
SDHCI_DUMP
(
"Blk size:
0x%08x | Blk cnt: 0x%08x
\n
"
,
sdhci_readw
(
host
,
SDHCI_BLOCK_SIZE
),
sdhci_readw
(
host
,
SDHCI_BLOCK_COUNT
));
pr_err
(
DRIVER_NAME
": Argument:
0x%08x | Trn mode: 0x%08x
\n
"
,
SDHCI_DUMP
(
"Argument:
0x%08x | Trn mode: 0x%08x
\n
"
,
sdhci_readl
(
host
,
SDHCI_ARGUMENT
),
sdhci_readw
(
host
,
SDHCI_TRANSFER_MODE
));
pr_err
(
DRIVER_NAME
": Present:
0x%08x | Host ctl: 0x%08x
\n
"
,
SDHCI_DUMP
(
"Present:
0x%08x | Host ctl: 0x%08x
\n
"
,
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
),
sdhci_readb
(
host
,
SDHCI_HOST_CONTROL
));
pr_err
(
DRIVER_NAME
": Power:
0x%08x | Blk gap: 0x%08x
\n
"
,
SDHCI_DUMP
(
"Power:
0x%08x | Blk gap: 0x%08x
\n
"
,
sdhci_readb
(
host
,
SDHCI_POWER_CONTROL
),
sdhci_readb
(
host
,
SDHCI_BLOCK_GAP_CONTROL
));
pr_err
(
DRIVER_NAME
": Wake-up:
0x%08x | Clock: 0x%08x
\n
"
,
SDHCI_DUMP
(
"Wake-up:
0x%08x | Clock: 0x%08x
\n
"
,
sdhci_readb
(
host
,
SDHCI_WAKE_UP_CONTROL
),
sdhci_readw
(
host
,
SDHCI_CLOCK_CONTROL
));
pr_err
(
DRIVER_NAME
": Timeout:
0x%08x | Int stat: 0x%08x
\n
"
,
SDHCI_DUMP
(
"Timeout:
0x%08x | Int stat: 0x%08x
\n
"
,
sdhci_readb
(
host
,
SDHCI_TIMEOUT_CONTROL
),
sdhci_readl
(
host
,
SDHCI_INT_STATUS
));
pr_err
(
DRIVER_NAME
": Int enab:
0x%08x | Sig enab: 0x%08x
\n
"
,
SDHCI_DUMP
(
"Int enab:
0x%08x | Sig enab: 0x%08x
\n
"
,
sdhci_readl
(
host
,
SDHCI_INT_ENABLE
),
sdhci_readl
(
host
,
SDHCI_SIGNAL_ENABLE
));
pr_err
(
DRIVER_NAME
": AC12 err:
0x%08x | Slot int: 0x%08x
\n
"
,
SDHCI_DUMP
(
"AC12 err:
0x%08x | Slot int: 0x%08x
\n
"
,
sdhci_readw
(
host
,
SDHCI_ACMD12_ERR
),
sdhci_readw
(
host
,
SDHCI_SLOT_INT_STATUS
));
pr_err
(
DRIVER_NAME
": Caps:
0x%08x | Caps_1: 0x%08x
\n
"
,
SDHCI_DUMP
(
"Caps:
0x%08x | Caps_1: 0x%08x
\n
"
,
sdhci_readl
(
host
,
SDHCI_CAPABILITIES
),
sdhci_readl
(
host
,
SDHCI_CAPABILITIES_1
));
pr_err
(
DRIVER_NAME
": Cmd:
0x%08x | Max curr: 0x%08x
\n
"
,
SDHCI_DUMP
(
"Cmd:
0x%08x | Max curr: 0x%08x
\n
"
,
sdhci_readw
(
host
,
SDHCI_COMMAND
),
sdhci_readl
(
host
,
SDHCI_MAX_CURRENT
));
pr_err
(
DRIVER_NAME
": Host ctl2: 0x%08x
\n
"
,
SDHCI_DUMP
(
"Resp[0]: 0x%08x | Resp[1]: 0x%08x
\n
"
,
sdhci_readl
(
host
,
SDHCI_RESPONSE
),
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_64_BIT_DMA
)
pr_err
(
DRIVER_NAME
": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x
\n
"
,
readl
(
host
->
ioaddr
+
SDHCI_ADMA_ERROR
),
readl
(
host
->
ioaddr
+
SDHCI_ADMA_ADDRESS_HI
),
readl
(
host
->
ioaddr
+
SDHCI_ADMA_ADDRESS
));
else
pr_err
(
DRIVER_NAME
": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x
\n
"
,
readl
(
host
->
ioaddr
+
SDHCI_ADMA_ERROR
),
readl
(
host
->
ioaddr
+
SDHCI_ADMA_ADDRESS
));
if
(
host
->
flags
&
SDHCI_USE_64_BIT_DMA
)
{
SDHCI_DUMP
(
"ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x
\n
"
,
sdhci_readl
(
host
,
SDHCI_ADMA_ERROR
),
sdhci_readl
(
host
,
SDHCI_ADMA_ADDRESS_HI
),
sdhci_readl
(
host
,
SDHCI_ADMA_ADDRESS
));
}
else
{
SDHCI_DUMP
(
"ADMA Err: 0x%08x | ADMA Ptr: 0x%08x
\n
"
,
sdhci_readl
(
host
,
SDHCI_ADMA_ERROR
),
sdhci_readl
(
host
,
SDHCI_ADMA_ADDRESS
));
}
}
pr_err
(
DRIVER_NAME
":
===========================================
\n
"
);
SDHCI_DUMP
(
"=
===========================================
\n
"
);
}
EXPORT_SYMBOL_GPL
(
sdhci_dumpregs
);
/*****************************************************************************\
* *
...
...
@@ -125,7 +137,7 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
if
(
enable
)
{
present
=
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
)
&
// Elphel
//
SDHCI_CARD_PRESENT;
//
SDHCI_CARD_PRESENT;
SDHCI_ANY_PRESENT
;
host
->
ier
|=
present
?
SDHCI_INT_CARD_REMOVE
:
...
...
@@ -166,7 +178,7 @@ static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
void
sdhci_reset
(
struct
sdhci_host
*
host
,
u8
mask
)
{
unsigned
long
timeout
;
ktime_t
timeout
;
sdhci_writeb
(
host
,
mask
,
SDHCI_SOFTWARE_RESET
);
...
...
@@ -178,18 +190,17 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
}
/* Wait max 100 ms */
timeout
=
100
;
timeout
=
ktime_add_ms
(
ktime_get
(),
100
)
;
/* hw clears the bit when it's done */
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
"
,
mmc_hostname
(
host
->
mmc
),
(
int
)
mask
);
sdhci_dumpregs
(
host
);
return
;
}
timeout
--
;
mdelay
(
1
);
udelay
(
10
);
}
}
EXPORT_SYMBOL_GPL
(
sdhci_reset
);
...
...
@@ -204,7 +215,6 @@ static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
if (!mmc->ops->get_cd(mmc))
return;
*/
// Elphel: this is old code
if
(
!
(
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
)
&
SDHCI_ANY_PRESENT
)){
...
...
@@ -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
|
SDHCI_INT_DATA_CRC
|
SDHCI_INT_DATA_TIMEOUT
|
SDHCI_INT_INDEX
|
SDHCI_INT_END_BIT
|
SDHCI_INT_CRC
|
...
...
@@ -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_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
)
{
/* force clock reconfiguration */
...
...
@@ -495,8 +512,7 @@ static int sdhci_pre_dma_transfer(struct sdhci_host *host,
return
data
->
sg_count
;
sg_count
=
dma_map_sg
(
mmc_dev
(
host
->
mmc
),
data
->
sg
,
data
->
sg_len
,
data
->
flags
&
MMC_DATA_WRITE
?
DMA_TO_DEVICE
:
DMA_FROM_DEVICE
);
mmc_get_dma_dir
(
data
));
if
(
sg_count
==
0
)
return
-
ENOSPC
;
...
...
@@ -725,8 +741,8 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
}
if
(
count
>=
0xF
)
{
DBG
(
"
%s:
Too large timeout 0x%x requested for CMD%d!
\n
"
,
mmc_hostname
(
host
->
mmc
),
count
,
cmd
->
opcode
);
DBG
(
"Too large timeout 0x%x requested for CMD%d!
\n
"
,
count
,
cmd
->
opcode
);
count
=
0xE
;
}
...
...
@@ -891,8 +907,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
sdhci_set_transfer_irqs
(
host
);
/* Set the DMA boundary value and block size */
sdhci_writew
(
host
,
SDHCI_MAKE_BLKSZ
(
SDHCI_DEFAULT_BOUNDARY_ARG
,
data
->
blksz
),
SDHCI_BLOCK_SIZE
);
sdhci_writew
(
host
,
SDHCI_MAKE_BLKSZ
(
host
->
sdma_boundary
,
data
->
blksz
)
,
SDHCI_BLOCK_SIZE
);
sdhci_writew
(
host
,
data
->
blocks
,
SDHCI_BLOCK_COUNT
);
}
...
...
@@ -1167,24 +1183,35 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
}
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
)
{
struct
mmc_command
*
cmd
=
host
->
cmd
;
int
i
;
host
->
cmd
=
NULL
;
if
(
cmd
->
flags
&
MMC_RSP_PRESENT
)
{
if
(
cmd
->
flags
&
MMC_RSP_136
)
{
/* CRC is stripped so we need to do some shifting. */
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
);
}
sdhci_read_rsp_136
(
host
,
cmd
);
}
else
{
cmd
->
resp
[
0
]
=
sdhci_readl
(
host
,
SDHCI_RESPONSE
);
}
...
...
@@ -1354,40 +1381,45 @@ clock_set:
}
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
;
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
);
ktime_t
timeout
;
clk
|=
SDHCI_CLOCK_INT_EN
;
sdhci_writew
(
host
,
clk
,
SDHCI_CLOCK_CONTROL
);
/* Wait max 20 ms */
timeout
=
20
;
timeout
=
ktime_add_ms
(
ktime_get
(),
20
)
;
while
(
!
((
clk
=
sdhci_readw
(
host
,
SDHCI_CLOCK_CONTROL
))
&
SDHCI_CLOCK_INT_STABLE
))
{
if
(
timeout
==
0
)
{
if
(
ktime_after
(
ktime_get
(),
timeout
)
)
{
pr_err
(
"%s: Internal clock never stabilised.
\n
"
,
mmc_hostname
(
host
->
mmc
));
sdhci_dumpregs
(
host
);
return
;
}
timeout
--
;
mdelay
(
1
);
udelay
(
10
);
}
clk
|=
SDHCI_CLOCK_CARD_EN
;
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
);
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
;
spin_unlock_irq
(
&
host
->
lock
);
mmc_regulator_set_ocr
(
mmc
,
mmc
->
supply
.
vmmc
,
vdd
);
spin_lock_irq
(
&
host
->
lock
);
if
(
mode
!=
MMC_POWER_OFF
)
sdhci_writeb
(
host
,
SDHCI_POWER_ON
,
SDHCI_POWER_CONTROL
);
...
...
@@ -1545,10 +1575,9 @@ void sdhci_set_bus_width(struct sdhci_host *host, int width)
ctrl
=
sdhci_readb
(
host
,
SDHCI_HOST_CONTROL
);
if
(
width
==
MMC_BUS_WIDTH_8
)
{
ctrl
&=
~
SDHCI_CTRL_4BITBUS
;
if
(
host
->
version
>=
SDHCI_SPEC_300
)
ctrl
|=
SDHCI_CTRL_8BITBUS
;
}
else
{
if
(
host
->
version
>=
SDHCI_SPEC_300
)
if
(
host
->
mmc
->
caps
&
MMC_CAP_8_BIT_DATA
)
ctrl
&=
~
SDHCI_CTRL_8BITBUS
;
if
(
width
==
MMC_BUS_WIDTH_4
)
ctrl
|=
SDHCI_CTRL_4BITBUS
;
...
...
@@ -1584,16 +1613,15 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
}
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
);
unsigned
long
flags
;
u8
ctrl
;
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
if
(
ios
->
power_mode
==
MMC_POWER_UNDEFINED
)
return
;
if
(
host
->
flags
&
SDHCI_DEVICE_DEAD
)
{
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
if
(
!
IS_ERR
(
mmc
->
supply
.
vmmc
)
&&
ios
->
power_mode
==
MMC_POWER_OFF
)
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)
ctrl
=
sdhci_readb
(
host
,
SDHCI_HOST_CONTROL
);
if
((
ios
->
timing
==
MMC_TIMING_SD_HS
||
ios
->
timing
==
MMC_TIMING_MMC_HS
)
&&
!
(
host
->
quirks
&
SDHCI_QUIRK_NO_HISPD_BIT
))
if
(
!
(
host
->
quirks
&
SDHCI_QUIRK_NO_HISPD_BIT
))
{
if
(
ios
->
timing
==
MMC_TIMING_SD_HS
||
ios
->
timing
==
MMC_TIMING_MMC_HS
||
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
;
else
ctrl
&=
~
SDHCI_CTRL_HISPD
;
}
if
(
host
->
version
>=
SDHCI_SPEC_300
)
{
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
)
{
sdhci_writeb
(
host
,
ctrl
,
SDHCI_HOST_CONTROL
);
/*
...
...
@@ -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
);
mmiowb
();
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
}
EXPORT_SYMBOL_GPL
(
sdhci_set_ios
);
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)
}
}
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
);
unsigned
long
flags
;
if
(
enable
)
pm_runtime_get_noresume
(
host
->
mmc
->
parent
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
if
(
enable
)
host
->
flags
|=
SDHCI_SDIO_IRQ_ENABLED
;
...
...
@@ -1852,9 +1881,13 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
sdhci_enable_sdio_irq_nolock
(
host
,
enable
);
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
sdhci_host
*
host
=
mmc_priv
(
mmc
);
...
...
@@ -1947,6 +1980,7 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
return
0
;
}
}
EXPORT_SYMBOL_GPL
(
sdhci_start_signal_voltage_switch
);
static
int
sdhci_card_busy
(
struct
mmc_host
*
mmc
)
{
...
...
@@ -1971,64 +2005,9 @@ static int sdhci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
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
;
int
tuning_loop_counter
=
MAX_TUNING_LOOP
;
int
err
=
0
;
unsigned
long
flags
;
unsigned
int
tuning_count
=
0
;
bool
hs400_tuning
;
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
hs400_tuning
=
host
->
flags
&
SDHCI_HS400_TUNING
;
host
->
flags
&=
~
SDHCI_HS400_TUNING
;
if
(
host
->
tuning_mode
==
SDHCI_TUNING_MODE_1
)
tuning_count
=
host
->
tuning_count
;
/*
* The Host Controller needs tuning in case of SDR104 and DDR50
* mode, and for SDR50 mode when Use Tuning for SDR50 is set in
* the Capabilities register.
* If the Host Controller supports the HS200 mode then the
* tuning function has to be executed.
*/
switch
(
host
->
timing
)
{
/* HS400 tuning is done in HS200 mode */
case
MMC_TIMING_MMC_HS400
:
err
=
-
EINVAL
;
goto
out_unlock
;
case
MMC_TIMING_MMC_HS200
:
/*
* Periodic re-tuning for HS400 is not expected to be needed, so
* disable it here.
*/
if
(
hs400_tuning
)
tuning_count
=
0
;
break
;
case
MMC_TIMING_UHS_SDR104
:
case
MMC_TIMING_UHS_DDR50
:
break
;
case
MMC_TIMING_UHS_SDR50
:
if
(
host
->
flags
&
SDHCI_SDR50_NEEDS_TUNING
)
break
;
/* FALLTHROUGH */
default:
goto
out_unlock
;
}
if
(
host
->
ops
->
platform_execute_tuning
)
{
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
err
=
host
->
ops
->
platform_execute_tuning
(
host
,
opcode
);
return
err
;
}
ctrl
=
sdhci_readw
(
host
,
SDHCI_HOST_CONTROL2
);
ctrl
|=
SDHCI_CTRL_EXEC_TUNING
;
...
...
@@ -2048,44 +2027,68 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
*/
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.
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.
*/
do
{
struct
mmc_command
cmd
=
{
0
};
struct
mmc_request
mrq
=
{
NULL
};
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
;
u32
b
=
host
->
sdma_boundary
;
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
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
);
}
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.
...
...
@@ -2098,85 +2101,125 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
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
),
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
);
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
);
ctrl
&=
~
SDHCI_CTRL_TUNED_CLK
;
ctrl
&=
~
SDHCI_CTRL_EXEC_TUNING
;
sdhci_writew
(
host
,
ctrl
,
SDHCI_HOST_CONTROL2
);
if
(
!
(
ctrl
&
SDHCI_CTRL_EXEC_TUNING
))
{
if
(
ctrl
&
SDHCI_CTRL_TUNED_CLK
)
return
;
/* Success! */
break
;
}
err
=
-
EIO
;
goto
out
;
/* Spec does not require a delay between tuning cycles */
if
(
host
->
tuning_delay
>
0
)
mdelay
(
host
->
tuning_delay
);
}
host
->
tuning_done
=
0
;
pr_info
(
"%s: Tuning failed, falling back to fixed sampling clock
\n
"
,
mmc_hostname
(
host
->
mmc
));
sdhci_reset_tuning
(
host
);
}
ctrl
=
sdhci_readw
(
host
,
SDHCI_HOST_CONTROL2
);
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
;
/* eMMC spec does not require a delay between tuning cycles */
if
(
opcode
==
MMC_SEND_TUNING_BLOCK
)
mdelay
(
1
);
}
while
(
ctrl
&
SDHCI_CTRL_EXEC_TUNING
)
;
hs400_tuning
=
host
->
flags
&
SDHCI_HS400_TUNING
;
if
(
host
->
tuning_mode
==
SDHCI_TUNING_MODE_1
)
tuning_count
=
host
->
tuning_count
;
/*
* The Host Driver has exhausted the maximum number of loops allowed,
* so use fixed sampling frequency.
* The Host Controller needs tuning in case of SDR104 and DDR50
* mode, and for SDR50 mode when Use Tuning for SDR50 is set in
* the Capabilities register.
* If the Host Controller supports the HS200 mode then the
* tuning function has to be executed.
*/
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
;
}
switch
(
host
->
timing
)
{
/* HS400 tuning is done in HS200 mode */
case
MMC_TIMING_MMC_HS400
:
err
=
-
EINVAL
;
goto
out
;
out:
if
(
tuning_count
)
{
case
MMC_TIMING_MMC_HS200
:
/*
* 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.
* Periodic re-tuning for HS400 is not expected to be needed, so
* disable it here.
*/
err
=
0
;
if
(
hs400_tuning
)
tuning_count
=
0
;
break
;
case
MMC_TIMING_UHS_SDR104
:
case
MMC_TIMING_UHS_DDR50
:
break
;
case
MMC_TIMING_UHS_SDR50
:
if
(
host
->
flags
&
SDHCI_SDR50_NEEDS_TUNING
)
break
;
/* FALLTHROUGH */
default:
goto
out
;
}
host
->
mmc
->
retune_period
=
err
?
0
:
tuning_count
;
if
(
host
->
ops
->
platform_execute_tuning
)
{
err
=
host
->
ops
->
platform_execute_tuning
(
host
,
opcode
);
goto
out
;
}
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
;
}
host
->
mmc
->
retune_period
=
tuning_count
;
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
->
tuning_delay
<
0
)
host
->
tuning_delay
=
opcode
==
MMC_SEND_TUNING_BLOCK
;
if
(
!
host
->
ops
->
select_drive_strength
)
return
0
;
sdhci_start_tuning
(
host
);
__sdhci_execute_tuning
(
host
,
opcode
);
sdhci_end_tuning
(
host
);
out:
host
->
flags
&=
~
SDHCI_HS400_TUNING
;
return
host
->
ops
->
select_drive_strength
(
host
,
card
,
max_dtr
,
host_drv
,
card_drv
,
drv_type
);
return
err
;
}
EXPORT_SYMBOL_GPL
(
sdhci_execute_tuning
);
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,
if
(
data
->
host_cookie
!=
COOKIE_UNMAPPED
)
dma_unmap_sg
(
mmc_dev
(
host
->
mmc
),
data
->
sg
,
data
->
sg_len
,
data
->
flags
&
MMC_DATA_WRITE
?
DMA_TO_DEVICE
:
DMA_FROM_DEVICE
);
mmc_get_dma_dir
(
data
));
data
->
host_cookie
=
COOKIE_UNMAPPED
;
}
static
void
sdhci_pre_req
(
struct
mmc_host
*
mmc
,
struct
mmc_request
*
mrq
,
bool
is_first_req
)
static
void
sdhci_pre_req
(
struct
mmc_host
*
mmc
,
struct
mmc_request
*
mrq
)
{
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
...
...
@@ -2292,7 +2333,6 @@ static const struct mmc_host_ops sdhci_ops = {
.
start_signal_voltage_switch
=
sdhci_start_signal_voltage_switch
,
.
prepare_hs400_tuning
=
sdhci_prepare_hs400_tuning
,
.
execute_tuning
=
sdhci_execute_tuning
,
.
select_drive_strength
=
sdhci_select_drive_strength
,
.
card_event
=
sdhci_card_event
,
.
card_busy
=
sdhci_card_busy
,
};
...
...
@@ -2334,8 +2374,7 @@ static bool sdhci_request_done(struct sdhci_host *host)
if
(
data
&&
data
->
host_cookie
==
COOKIE_MAPPED
)
{
dma_unmap_sg
(
mmc_dev
(
host
->
mmc
),
data
->
sg
,
data
->
sg_len
,
(
data
->
flags
&
MMC_DATA_READ
)
?
DMA_FROM_DEVICE
:
DMA_TO_DEVICE
);
mmc_get_dma_dir
(
data
));
data
->
host_cookie
=
COOKIE_UNMAPPED
;
}
}
...
...
@@ -2497,10 +2536,8 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
sdhci_finish_command
(
host
);
}
#ifdef CONFIG_MMC_DEBUG
static
void
sdhci_adma_show_error
(
struct
sdhci_host
*
host
)
{
const
char
*
name
=
mmc_hostname
(
host
->
mmc
);
void
*
desc
=
host
->
adma_table
;
sdhci_dumpregs
(
host
);
...
...
@@ -2509,14 +2546,14 @@ static void sdhci_adma_show_error(struct sdhci_host *host)
struct
sdhci_adma2_64_desc
*
dma_desc
=
desc
;
if
(
host
->
flags
&
SDHCI_USE_64_BIT_DMA
)
DBG
(
"%
s: %
p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x
\n
"
,
name
,
desc
,
le32_to_cpu
(
dma_desc
->
addr_hi
),
DBG
(
"%p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x
\n
"
,
desc
,
le32_to_cpu
(
dma_desc
->
addr_hi
),
le32_to_cpu
(
dma_desc
->
addr_lo
),
le16_to_cpu
(
dma_desc
->
len
),
le16_to_cpu
(
dma_desc
->
cmd
));
else
DBG
(
"%
s: %
p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x
\n
"
,
name
,
desc
,
le32_to_cpu
(
dma_desc
->
addr_lo
),
DBG
(
"%p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x
\n
"
,
desc
,
le32_to_cpu
(
dma_desc
->
addr_lo
),
le16_to_cpu
(
dma_desc
->
len
),
le16_to_cpu
(
dma_desc
->
cmd
));
...
...
@@ -2526,9 +2563,6 @@ static void sdhci_adma_show_error(struct sdhci_host *host)
break
;
}
}
#else
static
void
sdhci_adma_show_error
(
struct
sdhci_host
*
host
)
{
}
#endif
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
;
host
->
data
->
bytes_xfered
=
dmanow
-
dmastart
;
DBG
(
"%s: DMA base 0x%08x, transferred 0x%06x bytes,"
" next 0x%08x
\n
"
,
mmc_hostname
(
host
->
mmc
),
dmastart
,
host
->
data
->
bytes_xfered
,
dmanow
);
DBG
(
"DMA base 0x%08x, transferred 0x%06x bytes, next 0x%08x
\n
"
,
dmastart
,
host
->
data
->
bytes_xfered
,
dmanow
);
sdhci_writel
(
host
,
dmanow
,
SDHCI_DMA_ADDRESS
);
}
...
...
@@ -2675,14 +2707,19 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
}
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. */
mask
=
intmask
&
(
SDHCI_INT_CMD_MASK
|
SDHCI_INT_DATA_MASK
|
SDHCI_INT_BUS_POWER
);
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
))
{
u32
present
=
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
)
&
// Elphel
...
...
@@ -2728,7 +2765,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
if
(
intmask
&
SDHCI_INT_RETUNE
)
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
);
host
->
thread_isr
|=
SDHCI_INT_CARD_INT
;
result
=
IRQ_WAKE_THREAD
;
...
...
@@ -2743,7 +2781,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
unexpected
|=
intmask
;
sdhci_writel
(
host
,
intmask
,
SDHCI_INT_STATUS
);
}
cont:
if
(
result
==
IRQ_NONE
)
result
=
IRQ_HANDLED
;
...
...
@@ -2842,8 +2880,6 @@ int sdhci_suspend_host(struct sdhci_host *host)
sdhci_disable_card_detection
(
host
);
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
)))
{
host
->
ier
=
0
;
...
...
@@ -2904,8 +2940,6 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
unsigned
long
flags
;
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
);
host
->
ier
&=
SDHCI_INT_CARD_INT
;
...
...
@@ -2936,6 +2970,8 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
sdhci_init
(
host
,
0
);
if
(
mmc
->
ios
.
power_mode
!=
MMC_POWER_UNDEFINED
&&
mmc
->
ios
.
power_mode
!=
MMC_POWER_OFF
)
{
/* Force clock and power re-program */
host
->
pwr
=
0
;
host
->
clock
=
0
;
...
...
@@ -2952,6 +2988,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
if
((
mmc
->
caps2
&
MMC_CAP2_HS400_ES
)
&&
mmc
->
ops
->
hs400_enhanced_strobe
)
mmc
->
ops
->
hs400_enhanced_strobe
(
mmc
,
&
mmc
->
ios
);
}
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
...
...
@@ -2972,6 +3009,119 @@ EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host);
#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 *
...
...
@@ -2997,6 +3147,13 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
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
;
}
...
...
@@ -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
)
{
u16
v
;
u64
dt_caps_mask
=
0
;
u64
dt_caps
=
0
;
if
(
host
->
read_caps
)
return
;
...
...
@@ -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
);
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
);
host
->
version
=
(
v
&
SDHCI_SPEC_VER_MASK
)
>>
SDHCI_SPEC_VER_SHIFT
;
if
(
host
->
quirks
&
SDHCI_QUIRK_MISSING_CAPS
)
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
)
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
);
...
...
@@ -3089,6 +3265,13 @@ int sdhci_setup_host(struct sdhci_host *host)
if
(
ret
==
-
EPROBE_DEFER
)
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
);
override_timeout_clk
=
host
->
timeout_clk
;
...
...
@@ -3260,20 +3443,22 @@ int sdhci_setup_host(struct sdhci_host *host)
if
(
!
(
host
->
quirks
&
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
))
{
host
->
timeout_clk
=
(
host
->
caps
&
SDHCI_TIMEOUT_CLK_MASK
)
>>
SDHCI_TIMEOUT_CLK_SHIFT
;
if
(
host
->
caps
&
SDHCI_TIMEOUT_CLK_UNIT
)
host
->
timeout_clk
*=
1000
;
if
(
host
->
timeout_clk
==
0
)
{
if
(
host
->
ops
->
get_timeout_clock
)
{
host
->
timeout_clk
=
host
->
ops
->
get_timeout_clock
(
host
);
}
else
{
if
(
!
host
->
ops
->
get_timeout_clock
)
{
pr_err
(
"%s: Hardware doesn't specify timeout clock frequency.
\n
"
,
mmc_hostname
(
mmc
));
ret
=
-
ENODEV
;
goto
undma
;
}
}
if
(
host
->
caps
&
SDHCI_TIMEOUT_CLK_UNIT
)
host
->
timeout_clk
*=
1000
;
host
->
timeout_clk
=
DIV_ROUND_UP
(
host
->
ops
->
get_timeout_clock
(
host
),
1000
);
}
if
(
override_timeout_clk
)
host
->
timeout_clk
=
override_timeout_clk
;
...
...
@@ -3295,9 +3480,9 @@ int sdhci_setup_host(struct sdhci_host *host)
!
(
host
->
flags
&
SDHCI_USE_SDMA
))
&&
!
(
host
->
quirks2
&
SDHCI_QUIRK2_ACMD23_BROKEN
))
{
host
->
flags
|=
SDHCI_AUTO_CMD23
;
DBG
(
"
%s: Auto-CMD23 available
\n
"
,
mmc_hostname
(
mmc
)
);
DBG
(
"
Auto-CMD23 available
\n
"
);
}
else
{
DBG
(
"
%s: Auto-CMD23 unavailable
\n
"
,
mmc_hostname
(
mmc
)
);
DBG
(
"
Auto-CMD23 unavailable
\n
"
);
}
/*
...
...
@@ -3562,6 +3747,22 @@ undma:
}
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
)
{
struct
mmc_host
*
mmc
=
host
->
mmc
;
...
...
@@ -3589,10 +3790,6 @@ int __sdhci_add_host(struct sdhci_host *host)
goto
untasklet
;
}
#ifdef CONFIG_MMC_DEBUG
sdhci_dumpregs
(
host
);
#endif
ret
=
sdhci_led_register
(
host
);
if
(
ret
)
{
pr_err
(
"%s: Failed to register LED device: %d
\n
"
,
...
...
@@ -3626,16 +3823,6 @@ unirq:
untasklet:
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
;
}
EXPORT_SYMBOL_GPL
(
__sdhci_add_host
);
...
...
@@ -3648,7 +3835,16 @@ int sdhci_add_host(struct sdhci_host *host)
if
(
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
);
...
...
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