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
fb001670
Commit
fb001670
authored
Nov 22, 2017
by
Oleg Dzhimiev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
udpated
parent
8cb401ab
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
1304 additions
and
943 deletions
+1304
-943
sdhci.c
src/drivers/mmc/host/sdhci.c
+1052
-933
sdhci.h
src/drivers/mmc/host/sdhci.h
+252
-10
No files found.
src/drivers/mmc/host/sdhci.c
View file @
fb001670
...
@@ -28,6 +28,7 @@
...
@@ -28,6 +28,7 @@
#include <linux/mmc/mmc.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/host.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/card.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/mmc/slot-gpio.h>
#include "sdhci.h"
#include "sdhci.h"
...
@@ -37,11 +38,6 @@
...
@@ -37,11 +38,6 @@
#define DBG(f, x...) \
#define DBG(f, x...) \
pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
#if defined(CONFIG_LEDS_CLASS) || (defined(CONFIG_LEDS_CLASS_MODULE) && \
defined(CONFIG_MMC_SDHCI_MODULE))
#define SDHCI_USE_LEDS_CLASS
#endif
#define MAX_TUNING_LOOP 40
#define MAX_TUNING_LOOP 40
static
unsigned
int
debug_quirks
=
0
;
static
unsigned
int
debug_quirks
=
0
;
...
@@ -49,90 +45,62 @@ static unsigned int debug_quirks2;
...
@@ -49,90 +45,62 @@ static unsigned int debug_quirks2;
static
void
sdhci_finish_data
(
struct
sdhci_host
*
);
static
void
sdhci_finish_data
(
struct
sdhci_host
*
);
static
void
sdhci_finish_command
(
struct
sdhci_host
*
);
static
int
sdhci_execute_tuning
(
struct
mmc_host
*
mmc
,
u32
opcode
);
static
void
sdhci_tuning_timer
(
unsigned
long
data
);
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
int
sdhci_pre_dma_transfer
(
struct
sdhci_host
*
host
,
struct
mmc_data
*
data
,
struct
sdhci_host_next
*
next
);
#ifdef CONFIG_PM
static
int
sdhci_runtime_pm_get
(
struct
sdhci_host
*
host
);
static
int
sdhci_runtime_pm_put
(
struct
sdhci_host
*
host
);
static
void
sdhci_runtime_pm_bus_on
(
struct
sdhci_host
*
host
);
static
void
sdhci_runtime_pm_bus_off
(
struct
sdhci_host
*
host
);
#else
static
inline
int
sdhci_runtime_pm_get
(
struct
sdhci_host
*
host
)
{
return
0
;
}
static
inline
int
sdhci_runtime_pm_put
(
struct
sdhci_host
*
host
)
{
return
0
;
}
static
void
sdhci_runtime_pm_bus_on
(
struct
sdhci_host
*
host
)
{
}
static
void
sdhci_runtime_pm_bus_off
(
struct
sdhci_host
*
host
)
{
}
#endif
static
void
sdhci_dumpregs
(
struct
sdhci_host
*
host
)
static
void
sdhci_dumpregs
(
struct
sdhci_host
*
host
)
{
{
pr_
debug
(
DRIVER_NAME
": =========== REGISTER DUMP (%s)===========
\n
"
,
pr_
err
(
DRIVER_NAME
": =========== REGISTER DUMP (%s)===========
\n
"
,
mmc_hostname
(
host
->
mmc
));
mmc_hostname
(
host
->
mmc
));
pr_
debug
(
DRIVER_NAME
": 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
));
pr_
debug
(
DRIVER_NAME
": 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
));
pr_
debug
(
DRIVER_NAME
": 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
));
pr_
debug
(
DRIVER_NAME
": 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
));
pr_
debug
(
DRIVER_NAME
": 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
));
pr_
debug
(
DRIVER_NAME
": 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
));
pr_
debug
(
DRIVER_NAME
": 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
));
pr_
debug
(
DRIVER_NAME
": 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
));
pr_
debug
(
DRIVER_NAME
": 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
));
pr_
debug
(
DRIVER_NAME
": 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
));
pr_
debug
(
DRIVER_NAME
": 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
));
pr_
debug
(
DRIVER_NAME
": Host ctl2: 0x%08x
\n
"
,
pr_
err
(
DRIVER_NAME
": Host ctl2: 0x%08x
\n
"
,
sdhci_readw
(
host
,
SDHCI_HOST_CONTROL2
));
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_
debug
(
DRIVER_NAME
": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x
\n
"
,
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_ERROR
),
readl
(
host
->
ioaddr
+
SDHCI_ADMA_ADDRESS_HI
),
readl
(
host
->
ioaddr
+
SDHCI_ADMA_ADDRESS_HI
),
readl
(
host
->
ioaddr
+
SDHCI_ADMA_ADDRESS
));
readl
(
host
->
ioaddr
+
SDHCI_ADMA_ADDRESS
));
else
else
pr_
debug
(
DRIVER_NAME
": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x
\n
"
,
pr_
err
(
DRIVER_NAME
": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x
\n
"
,
readl
(
host
->
ioaddr
+
SDHCI_ADMA_ERROR
),
readl
(
host
->
ioaddr
+
SDHCI_ADMA_ERROR
),
readl
(
host
->
ioaddr
+
SDHCI_ADMA_ADDRESS
));
readl
(
host
->
ioaddr
+
SDHCI_ADMA_ADDRESS
));
}
}
pr_
debug
(
DRIVER_NAME
": ===========================================
\n
"
);
pr_
err
(
DRIVER_NAME
": ===========================================
\n
"
);
}
}
/*****************************************************************************\
/*****************************************************************************\
...
@@ -141,27 +109,25 @@ static void sdhci_dumpregs(struct sdhci_host *host)
...
@@ -141,27 +109,25 @@ static void sdhci_dumpregs(struct sdhci_host *host)
* *
* *
\*****************************************************************************/
\*****************************************************************************/
static
inline
bool
sdhci_data_line_cmd
(
struct
mmc_command
*
cmd
)
{
return
cmd
->
data
||
cmd
->
flags
&
MMC_RSP_BUSY
;
}
static
void
sdhci_set_card_detection
(
struct
sdhci_host
*
host
,
bool
enable
)
static
void
sdhci_set_card_detection
(
struct
sdhci_host
*
host
,
bool
enable
)
{
{
u32
present
;
u32
present
;
if
((
host
->
quirks
&
SDHCI_QUIRK_BROKEN_CARD_DETECTION
)
||
if
((
host
->
quirks
&
SDHCI_QUIRK_BROKEN_CARD_DETECTION
)
||
(
host
->
mmc
->
caps
&
MMC_CAP_NONREMOVABLE
))
!
mmc_card_is_removable
(
host
->
mmc
))
return
;
return
;
if
(
enable
)
{
if
(
enable
)
{
present
=
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
)
&
present
=
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
)
&
// Elphel
// SDHCI_CARD_PRESENT;
SDHCI_ANY_PRESENT
;
SDHCI_ANY_PRESENT
;
/* oleg's debug
if (!present){
pr_err("Forcing Card Present\n");
present = SDHCI_ANY_PRESENT;
}else{
pr_err("Card Is Present\n");
}
*/
host
->
ier
|=
present
?
SDHCI_INT_CARD_REMOVE
:
host
->
ier
|=
present
?
SDHCI_INT_CARD_REMOVE
:
SDHCI_INT_CARD_INSERT
;
SDHCI_INT_CARD_INSERT
;
}
else
{
}
else
{
...
@@ -182,6 +148,22 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
...
@@ -182,6 +148,22 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
sdhci_set_card_detection
(
host
,
false
);
sdhci_set_card_detection
(
host
,
false
);
}
}
static
void
sdhci_runtime_pm_bus_on
(
struct
sdhci_host
*
host
)
{
if
(
host
->
bus_on
)
return
;
host
->
bus_on
=
true
;
pm_runtime_get_noresume
(
host
->
mmc
->
parent
);
}
static
void
sdhci_runtime_pm_bus_off
(
struct
sdhci_host
*
host
)
{
if
(
!
host
->
bus_on
)
return
;
host
->
bus_on
=
false
;
pm_runtime_put_noidle
(
host
->
mmc
->
parent
);
}
void
sdhci_reset
(
struct
sdhci_host
*
host
,
u8
mask
)
void
sdhci_reset
(
struct
sdhci_host
*
host
,
u8
mask
)
{
{
unsigned
long
timeout
;
unsigned
long
timeout
;
...
@@ -215,14 +197,20 @@ EXPORT_SYMBOL_GPL(sdhci_reset);
...
@@ -215,14 +197,20 @@ EXPORT_SYMBOL_GPL(sdhci_reset);
static
void
sdhci_do_reset
(
struct
sdhci_host
*
host
,
u8
mask
)
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
/*
struct mmc_host *mmc = host->mmc;
if (!mmc->ops->get_cd(mmc))
return;
*/
// 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
)){
// oleg's debug
//pr_err("!!!!!sdhci_doNOT_reset!!!!");
return
;
return
;
}
}
}
}
//pr_err("!!!!!sdhci_do_reset!!!!");
host
->
ops
->
reset
(
host
,
mask
);
host
->
ops
->
reset
(
host
,
mask
);
...
@@ -237,10 +225,10 @@ static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
...
@@ -237,10 +225,10 @@ static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
}
}
}
}
static
void
sdhci_set_ios
(
struct
mmc_host
*
mmc
,
struct
mmc_ios
*
ios
);
static
void
sdhci_init
(
struct
sdhci_host
*
host
,
int
soft
)
static
void
sdhci_init
(
struct
sdhci_host
*
host
,
int
soft
)
{
{
struct
mmc_host
*
mmc
=
host
->
mmc
;
if
(
soft
)
if
(
soft
)
sdhci_do_reset
(
host
,
SDHCI_RESET_CMD
|
SDHCI_RESET_DATA
);
sdhci_do_reset
(
host
,
SDHCI_RESET_CMD
|
SDHCI_RESET_DATA
);
else
else
...
@@ -252,34 +240,27 @@ static void sdhci_init(struct sdhci_host *host, int soft)
...
@@ -252,34 +240,27 @@ static void sdhci_init(struct sdhci_host *host, int soft)
SDHCI_INT_TIMEOUT
|
SDHCI_INT_DATA_END
|
SDHCI_INT_TIMEOUT
|
SDHCI_INT_DATA_END
|
SDHCI_INT_RESPONSE
;
SDHCI_INT_RESPONSE
;
if
(
host
->
tuning_mode
==
SDHCI_TUNING_MODE_2
||
host
->
tuning_mode
==
SDHCI_TUNING_MODE_3
)
host
->
ier
|=
SDHCI_INT_RETUNE
;
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
);
if
(
soft
)
{
if
(
soft
)
{
/* force clock reconfiguration */
/* force clock reconfiguration */
host
->
clock
=
0
;
host
->
clock
=
0
;
sdhci_set_ios
(
host
->
mmc
,
&
host
->
mmc
->
ios
);
mmc
->
ops
->
set_ios
(
mmc
,
&
mmc
->
ios
);
}
}
}
}
static
void
sdhci_reinit
(
struct
sdhci_host
*
host
)
static
void
sdhci_reinit
(
struct
sdhci_host
*
host
)
{
{
sdhci_init
(
host
,
0
);
sdhci_init
(
host
,
0
);
/*
* Retuning stuffs are affected by different cards inserted and only
* applicable to UHS-I cards. So reset these fields to their initial
* value when card is removed.
*/
if
(
host
->
flags
&
SDHCI_USING_RETUNING_TIMER
)
{
host
->
flags
&=
~
SDHCI_USING_RETUNING_TIMER
;
del_timer_sync
(
&
host
->
tuning_timer
);
host
->
flags
&=
~
SDHCI_NEEDS_RETUNING
;
}
sdhci_enable_card_detection
(
host
);
sdhci_enable_card_detection
(
host
);
}
}
static
void
sdhci_activate_led
(
struct
sdhci_host
*
host
)
static
void
__sdhci_led_activate
(
struct
sdhci_host
*
host
)
{
{
u8
ctrl
;
u8
ctrl
;
...
@@ -288,7 +269,7 @@ static void sdhci_activate_led(struct sdhci_host *host)
...
@@ -288,7 +269,7 @@ static void sdhci_activate_led(struct sdhci_host *host)
sdhci_writeb
(
host
,
ctrl
,
SDHCI_HOST_CONTROL
);
sdhci_writeb
(
host
,
ctrl
,
SDHCI_HOST_CONTROL
);
}
}
static
void
sdhci_deactivate_led
(
struct
sdhci_host
*
host
)
static
void
__sdhci_led_deactivate
(
struct
sdhci_host
*
host
)
{
{
u8
ctrl
;
u8
ctrl
;
...
@@ -297,7 +278,7 @@ static void sdhci_deactivate_led(struct sdhci_host *host)
...
@@ -297,7 +278,7 @@ static void sdhci_deactivate_led(struct sdhci_host *host)
sdhci_writeb
(
host
,
ctrl
,
SDHCI_HOST_CONTROL
);
sdhci_writeb
(
host
,
ctrl
,
SDHCI_HOST_CONTROL
);
}
}
#if
def SDHCI_USE_LEDS_CLASS
#if
IS_REACHABLE(CONFIG_LEDS_CLASS)
static
void
sdhci_led_control
(
struct
led_classdev
*
led
,
static
void
sdhci_led_control
(
struct
led_classdev
*
led
,
enum
led_brightness
brightness
)
enum
led_brightness
brightness
)
{
{
...
@@ -310,12 +291,62 @@ static void sdhci_led_control(struct led_classdev *led,
...
@@ -310,12 +291,62 @@ static void sdhci_led_control(struct led_classdev *led,
goto
out
;
goto
out
;
if
(
brightness
==
LED_OFF
)
if
(
brightness
==
LED_OFF
)
sdhci_deactivate_led
(
host
);
__sdhci_led_deactivate
(
host
);
else
else
sdhci_activate_led
(
host
);
__sdhci_led_activate
(
host
);
out:
out:
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
}
}
static
int
sdhci_led_register
(
struct
sdhci_host
*
host
)
{
struct
mmc_host
*
mmc
=
host
->
mmc
;
snprintf
(
host
->
led_name
,
sizeof
(
host
->
led_name
),
"%s::"
,
mmc_hostname
(
mmc
));
host
->
led
.
name
=
host
->
led_name
;
host
->
led
.
brightness
=
LED_OFF
;
host
->
led
.
default_trigger
=
mmc_hostname
(
mmc
);
host
->
led
.
brightness_set
=
sdhci_led_control
;
return
led_classdev_register
(
mmc_dev
(
mmc
),
&
host
->
led
);
}
static
void
sdhci_led_unregister
(
struct
sdhci_host
*
host
)
{
led_classdev_unregister
(
&
host
->
led
);
}
static
inline
void
sdhci_led_activate
(
struct
sdhci_host
*
host
)
{
}
static
inline
void
sdhci_led_deactivate
(
struct
sdhci_host
*
host
)
{
}
#else
static
inline
int
sdhci_led_register
(
struct
sdhci_host
*
host
)
{
return
0
;
}
static
inline
void
sdhci_led_unregister
(
struct
sdhci_host
*
host
)
{
}
static
inline
void
sdhci_led_activate
(
struct
sdhci_host
*
host
)
{
__sdhci_led_activate
(
host
);
}
static
inline
void
sdhci_led_deactivate
(
struct
sdhci_host
*
host
)
{
__sdhci_led_deactivate
(
host
);
}
#endif
#endif
/*****************************************************************************\
/*****************************************************************************\
...
@@ -339,8 +370,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
...
@@ -339,8 +370,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
local_irq_save
(
flags
);
local_irq_save
(
flags
);
while
(
blksize
)
{
while
(
blksize
)
{
if
(
!
sg_miter_next
(
&
host
->
sg_miter
))
BUG_ON
(
!
sg_miter_next
(
&
host
->
sg_miter
));
BUG
();
len
=
min
(
host
->
sg_miter
.
length
,
blksize
);
len
=
min
(
host
->
sg_miter
.
length
,
blksize
);
...
@@ -385,8 +415,7 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
...
@@ -385,8 +415,7 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
local_irq_save
(
flags
);
local_irq_save
(
flags
);
while
(
blksize
)
{
while
(
blksize
)
{
if
(
!
sg_miter_next
(
&
host
->
sg_miter
))
BUG_ON
(
!
sg_miter_next
(
&
host
->
sg_miter
));
BUG
();
len
=
min
(
host
->
sg_miter
.
length
,
blksize
);
len
=
min
(
host
->
sg_miter
.
length
,
blksize
);
...
@@ -419,8 +448,6 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
...
@@ -419,8 +448,6 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
{
{
u32
mask
;
u32
mask
;
BUG_ON
(
!
host
->
data
);
if
(
host
->
blocks
==
0
)
if
(
host
->
blocks
==
0
)
return
;
return
;
...
@@ -455,6 +482,31 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
...
@@ -455,6 +482,31 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
DBG
(
"PIO transfer complete.
\n
"
);
DBG
(
"PIO transfer complete.
\n
"
);
}
}
static
int
sdhci_pre_dma_transfer
(
struct
sdhci_host
*
host
,
struct
mmc_data
*
data
,
int
cookie
)
{
int
sg_count
;
/*
* If the data buffers are already mapped, return the previous
* dma_map_sg() result.
*/
if
(
data
->
host_cookie
==
COOKIE_PRE_MAPPED
)
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
);
if
(
sg_count
==
0
)
return
-
ENOSPC
;
data
->
sg_count
=
sg_count
;
data
->
host_cookie
=
cookie
;
return
sg_count
;
}
static
char
*
sdhci_kmap_atomic
(
struct
scatterlist
*
sg
,
unsigned
long
*
flags
)
static
char
*
sdhci_kmap_atomic
(
struct
scatterlist
*
sg
,
unsigned
long
*
flags
)
{
{
local_irq_save
(
*
flags
);
local_irq_save
(
*
flags
);
...
@@ -489,41 +541,22 @@ static void sdhci_adma_mark_end(void *desc)
...
@@ -489,41 +541,22 @@ static void sdhci_adma_mark_end(void *desc)
dma_desc
->
cmd
|=
cpu_to_le16
(
ADMA2_END
);
dma_desc
->
cmd
|=
cpu_to_le16
(
ADMA2_END
);
}
}
static
int
sdhci_adma_table_pre
(
struct
sdhci_host
*
host
,
static
void
sdhci_adma_table_pre
(
struct
sdhci_host
*
host
,
struct
mmc_data
*
data
)
struct
mmc_data
*
data
,
int
sg_count
)
{
{
int
direction
;
void
*
desc
;
void
*
align
;
dma_addr_t
addr
;
dma_addr_t
align_addr
;
int
len
,
offset
;
struct
scatterlist
*
sg
;
struct
scatterlist
*
sg
;
int
i
;
char
*
buffer
;
unsigned
long
flags
;
unsigned
long
flags
;
dma_addr_t
addr
,
align_addr
;
void
*
desc
,
*
align
;
char
*
buffer
;
int
len
,
offset
,
i
;
/*
/*
* The spec does not specify endianness of descriptor table.
* The spec does not specify endianness of descriptor table.
* We currently guess that it is LE.
* We currently guess that it is LE.
*/
*/
if
(
data
->
flags
&
MMC_DATA_READ
)
host
->
sg_count
=
sg_count
;
direction
=
DMA_FROM_DEVICE
;
else
direction
=
DMA_TO_DEVICE
;
host
->
align_addr
=
dma_map_single
(
mmc_dev
(
host
->
mmc
),
host
->
align_buffer
,
host
->
align_buffer_sz
,
direction
);
if
(
dma_mapping_error
(
mmc_dev
(
host
->
mmc
),
host
->
align_addr
))
goto
fail
;
BUG_ON
(
host
->
align_addr
&
host
->
align_mask
);
host
->
sg_count
=
sdhci_pre_dma_transfer
(
host
,
data
,
NULL
);
if
(
host
->
sg_count
<
0
)
goto
unmap_align
;
desc
=
host
->
adma_table
;
desc
=
host
->
adma_table
;
align
=
host
->
align_buffer
;
align
=
host
->
align_buffer
;
...
@@ -535,14 +568,13 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
...
@@ -535,14 +568,13 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
len
=
sg_dma_len
(
sg
);
len
=
sg_dma_len
(
sg
);
/*
/*
* The SDHCI specification states that ADMA
* The SDHCI specification states that ADMA addresses must
* addresses must be 32-bit aligned. If they
* be 32-bit aligned. If they aren't, then we use a bounce
* aren't, then we use a bounce buffer for
* buffer for the (up to three) bytes that screw up the
* the (up to three) bytes that screw up the
* alignment.
* alignment.
*/
*/
offset
=
(
host
->
align_sz
-
(
addr
&
host
->
align_mask
))
&
offset
=
(
SDHCI_ADMA2_ALIGN
-
(
addr
&
SDHCI_ADMA2_MASK
))
&
host
->
align_mask
;
SDHCI_ADMA2_MASK
;
if
(
offset
)
{
if
(
offset
)
{
if
(
data
->
flags
&
MMC_DATA_WRITE
)
{
if
(
data
->
flags
&
MMC_DATA_WRITE
)
{
buffer
=
sdhci_kmap_atomic
(
sg
,
&
flags
);
buffer
=
sdhci_kmap_atomic
(
sg
,
&
flags
);
...
@@ -556,8 +588,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
...
@@ -556,8 +588,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
BUG_ON
(
offset
>
65536
);
BUG_ON
(
offset
>
65536
);
align
+=
host
->
align_sz
;
align
+=
SDHCI_ADMA2_ALIGN
;
align_addr
+=
host
->
align_sz
;
align_addr
+=
SDHCI_ADMA2_ALIGN
;
desc
+=
host
->
desc_sz
;
desc
+=
host
->
desc_sz
;
...
@@ -567,9 +599,12 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
...
@@ -567,9 +599,12 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
BUG_ON
(
len
>
65536
);
BUG_ON
(
len
>
65536
);
if
(
len
)
{
/* tran, valid */
/* tran, valid */
sdhci_adma_write_desc
(
host
,
desc
,
addr
,
len
,
ADMA2_TRAN_VALID
);
sdhci_adma_write_desc
(
host
,
desc
,
addr
,
len
,
ADMA2_TRAN_VALID
);
desc
+=
host
->
desc_sz
;
desc
+=
host
->
desc_sz
;
}
/*
/*
* If this triggers then we have a calculation bug
* If this triggers then we have a calculation bug
...
@@ -579,90 +614,56 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
...
@@ -579,90 +614,56 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
}
}
if
(
host
->
quirks
&
SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
)
{
if
(
host
->
quirks
&
SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
)
{
/*
/* Mark the last descriptor as the terminating descriptor */
* Mark the last descriptor as the terminating descriptor
*/
if
(
desc
!=
host
->
adma_table
)
{
if
(
desc
!=
host
->
adma_table
)
{
desc
-=
host
->
desc_sz
;
desc
-=
host
->
desc_sz
;
sdhci_adma_mark_end
(
desc
);
sdhci_adma_mark_end
(
desc
);
}
}
}
else
{
}
else
{
/*
/* Add a terminating entry - nop, end, valid */
* Add a terminating entry.
*/
/* nop, end, valid */
sdhci_adma_write_desc
(
host
,
desc
,
0
,
0
,
ADMA2_NOP_END_VALID
);
sdhci_adma_write_desc
(
host
,
desc
,
0
,
0
,
ADMA2_NOP_END_VALID
);
}
}
/*
* Resync align buffer as we might have changed it.
*/
if
(
data
->
flags
&
MMC_DATA_WRITE
)
{
dma_sync_single_for_device
(
mmc_dev
(
host
->
mmc
),
host
->
align_addr
,
host
->
align_buffer_sz
,
direction
);
}
return
0
;
unmap_align:
dma_unmap_single
(
mmc_dev
(
host
->
mmc
),
host
->
align_addr
,
host
->
align_buffer_sz
,
direction
);
fail:
return
-
EINVAL
;
}
}
static
void
sdhci_adma_table_post
(
struct
sdhci_host
*
host
,
static
void
sdhci_adma_table_post
(
struct
sdhci_host
*
host
,
struct
mmc_data
*
data
)
struct
mmc_data
*
data
)
{
{
int
direction
;
struct
scatterlist
*
sg
;
struct
scatterlist
*
sg
;
int
i
,
size
;
int
i
,
size
;
void
*
align
;
void
*
align
;
char
*
buffer
;
char
*
buffer
;
unsigned
long
flags
;
unsigned
long
flags
;
bool
has_unaligned
;
if
(
data
->
flags
&
MMC_DATA_READ
)
if
(
data
->
flags
&
MMC_DATA_READ
)
{
direction
=
DMA_FROM_DEVICE
;
bool
has_unaligned
=
false
;
else
direction
=
DMA_TO_DEVICE
;
dma_unmap_single
(
mmc_dev
(
host
->
mmc
),
host
->
align_addr
,
host
->
align_buffer_sz
,
direction
);
/* Do a quick scan of the SG list for any unaligned mappings */
/* Do a quick scan of the SG list for any unaligned mappings */
has_unaligned
=
false
;
for_each_sg
(
data
->
sg
,
sg
,
host
->
sg_count
,
i
)
for_each_sg
(
data
->
sg
,
sg
,
host
->
sg_count
,
i
)
if
(
sg_dma_address
(
sg
)
&
host
->
align_mask
)
{
if
(
sg_dma_address
(
sg
)
&
SDHCI_ADMA2_MASK
)
{
has_unaligned
=
true
;
has_unaligned
=
true
;
break
;
break
;
}
}
if
(
has_unaligned
&&
data
->
flags
&
MMC_DATA_READ
)
{
if
(
has_unaligned
)
{
dma_sync_sg_for_cpu
(
mmc_dev
(
host
->
mmc
),
data
->
sg
,
dma_sync_sg_for_cpu
(
mmc_dev
(
host
->
mmc
),
data
->
sg
,
data
->
sg_len
,
direction
);
data
->
sg_len
,
DMA_FROM_DEVICE
);
align
=
host
->
align_buffer
;
align
=
host
->
align_buffer
;
for_each_sg
(
data
->
sg
,
sg
,
host
->
sg_count
,
i
)
{
for_each_sg
(
data
->
sg
,
sg
,
host
->
sg_count
,
i
)
{
if
(
sg_dma_address
(
sg
)
&
host
->
align_mask
)
{
if
(
sg_dma_address
(
sg
)
&
SDHCI_ADMA2_MASK
)
{
size
=
host
->
align_sz
-
size
=
SDHCI_ADMA2_ALIGN
-
(
sg_dma_address
(
sg
)
&
host
->
align_mask
);
(
sg_dma_address
(
sg
)
&
SDHCI_ADMA2_MASK
);
buffer
=
sdhci_kmap_atomic
(
sg
,
&
flags
);
buffer
=
sdhci_kmap_atomic
(
sg
,
&
flags
);
memcpy
(
buffer
,
align
,
size
);
memcpy
(
buffer
,
align
,
size
);
sdhci_kunmap_atomic
(
buffer
,
&
flags
);
sdhci_kunmap_atomic
(
buffer
,
&
flags
);
align
+=
host
->
align_sz
;
align
+=
SDHCI_ADMA2_ALIGN
;
}
}
}
}
}
}
}
if
(
!
data
->
host_cookie
)
dma_unmap_sg
(
mmc_dev
(
host
->
mmc
),
data
->
sg
,
data
->
sg_len
,
direction
);
}
}
static
u8
sdhci_calc_timeout
(
struct
sdhci_host
*
host
,
struct
mmc_command
*
cmd
)
static
u8
sdhci_calc_timeout
(
struct
sdhci_host
*
host
,
struct
mmc_command
*
cmd
)
...
@@ -688,9 +689,20 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
...
@@ -688,9 +689,20 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
if
(
!
data
)
if
(
!
data
)
target_timeout
=
cmd
->
busy_timeout
*
1000
;
target_timeout
=
cmd
->
busy_timeout
*
1000
;
else
{
else
{
target_timeout
=
data
->
timeout_ns
/
1000
;
target_timeout
=
DIV_ROUND_UP
(
data
->
timeout_ns
,
1000
);
if
(
host
->
clock
)
if
(
host
->
clock
&&
data
->
timeout_clks
)
{
target_timeout
+=
data
->
timeout_clks
/
host
->
clock
;
unsigned
long
long
val
;
/*
* data->timeout_clks is in units of clock cycles.
* host->clock is in Hz. target_timeout is in us.
* Hence, us = 1000000 * cycles / Hz. Round up.
*/
val
=
1000000ULL
*
data
->
timeout_clks
;
if
(
do_div
(
val
,
host
->
clock
))
target_timeout
++
;
target_timeout
+=
val
;
}
}
}
/*
/*
...
@@ -751,16 +763,15 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
...
@@ -751,16 +763,15 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
{
{
u8
ctrl
;
u8
ctrl
;
struct
mmc_data
*
data
=
cmd
->
data
;
struct
mmc_data
*
data
=
cmd
->
data
;
int
ret
;
WARN_ON
(
host
->
data
);
if
(
data
||
(
cmd
->
flags
&
MMC_RSP_BUSY
))
if
(
sdhci_data_line_cmd
(
cmd
))
sdhci_set_timeout
(
host
,
cmd
);
sdhci_set_timeout
(
host
,
cmd
);
if
(
!
data
)
if
(
!
data
)
return
;
return
;
WARN_ON
(
host
->
data
);
/* Sanity checks */
/* Sanity checks */
BUG_ON
(
data
->
blksz
*
data
->
blocks
>
524288
);
BUG_ON
(
data
->
blksz
*
data
->
blocks
>
524288
);
BUG_ON
(
data
->
blksz
>
host
->
mmc
->
max_blk_size
);
BUG_ON
(
data
->
blksz
>
host
->
mmc
->
max_blk_size
);
...
@@ -770,66 +781,49 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
...
@@ -770,66 +781,49 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
host
->
data_early
=
0
;
host
->
data_early
=
0
;
host
->
data
->
bytes_xfered
=
0
;
host
->
data
->
bytes_xfered
=
0
;
if
(
host
->
flags
&
(
SDHCI_USE_SDMA
|
SDHCI_USE_ADMA
))
if
(
host
->
flags
&
(
SDHCI_USE_SDMA
|
SDHCI_USE_ADMA
))
{
struct
scatterlist
*
sg
;
unsigned
int
length_mask
,
offset_mask
;
int
i
;
host
->
flags
|=
SDHCI_REQ_USE_DMA
;
host
->
flags
|=
SDHCI_REQ_USE_DMA
;
/*
/*
* FIXME: This doesn't account for merging when mapping the
* FIXME: This doesn't account for merging when mapping the
* scatterlist.
* scatterlist.
*
* The assumption here being that alignment and lengths are
* the same after DMA mapping to device address space.
*/
*/
if
(
host
->
flags
&
SDHCI_REQ_USE_DMA
)
{
length_mask
=
0
;
int
broken
,
i
;
offset_mask
=
0
;
struct
scatterlist
*
sg
;
broken
=
0
;
if
(
host
->
flags
&
SDHCI_USE_ADMA
)
{
if
(
host
->
flags
&
SDHCI_USE_ADMA
)
{
if
(
host
->
quirks
&
SDHCI_QUIRK_32BIT_ADMA_SIZE
)
if
(
host
->
quirks
&
SDHCI_QUIRK_32BIT_ADMA_SIZE
)
{
broken
=
1
;
length_mask
=
3
;
/*
* As we use up to 3 byte chunks to work
* around alignment problems, we need to
* check the offset as well.
*/
offset_mask
=
3
;
}
}
else
{
}
else
{
if
(
host
->
quirks
&
SDHCI_QUIRK_32BIT_DMA_SIZE
)
if
(
host
->
quirks
&
SDHCI_QUIRK_32BIT_DMA_SIZE
)
broken
=
1
;
length_mask
=
3
;
if
(
host
->
quirks
&
SDHCI_QUIRK_32BIT_DMA_ADDR
)
offset_mask
=
3
;
}
}
if
(
unlikely
(
broken
))
{
if
(
unlikely
(
length_mask
|
offset_mask
))
{
for_each_sg
(
data
->
sg
,
sg
,
data
->
sg_len
,
i
)
{
for_each_sg
(
data
->
sg
,
sg
,
data
->
sg_len
,
i
)
{
if
(
sg
->
length
&
0x3
)
{
if
(
sg
->
length
&
length_mask
)
{
DBG
(
"Reverting to PIO because of "
DBG
(
"Reverting to PIO because of transfer size (%d)
\n
"
,
"transfer size (%d)
\n
"
,
sg
->
length
);
sg
->
length
);
host
->
flags
&=
~
SDHCI_REQ_USE_DMA
;
host
->
flags
&=
~
SDHCI_REQ_USE_DMA
;
break
;
break
;
}
}
}
if
(
sg
->
offset
&
offset_mask
)
{
}
DBG
(
"Reverting to PIO because of bad alignment
\n
"
);
}
/*
* The assumption here being that alignment is the same after
* translation to device address space.
*/
if
(
host
->
flags
&
SDHCI_REQ_USE_DMA
)
{
int
broken
,
i
;
struct
scatterlist
*
sg
;
broken
=
0
;
if
(
host
->
flags
&
SDHCI_USE_ADMA
)
{
/*
* As we use 3 byte chunks to work around
* alignment problems, we need to check this
* quirk.
*/
if
(
host
->
quirks
&
SDHCI_QUIRK_32BIT_ADMA_SIZE
)
broken
=
1
;
}
else
{
if
(
host
->
quirks
&
SDHCI_QUIRK_32BIT_DMA_ADDR
)
broken
=
1
;
}
if
(
unlikely
(
broken
))
{
for_each_sg
(
data
->
sg
,
sg
,
data
->
sg_len
,
i
)
{
if
(
sg
->
offset
&
0x3
)
{
DBG
(
"Reverting to PIO because of "
"bad alignment
\n
"
);
host
->
flags
&=
~
SDHCI_REQ_USE_DMA
;
host
->
flags
&=
~
SDHCI_REQ_USE_DMA
;
break
;
break
;
}
}
...
@@ -838,41 +832,29 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
...
@@ -838,41 +832,29 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
}
}
if
(
host
->
flags
&
SDHCI_REQ_USE_DMA
)
{
if
(
host
->
flags
&
SDHCI_REQ_USE_DMA
)
{
i
f
(
host
->
flags
&
SDHCI_USE_ADMA
)
{
i
nt
sg_cnt
=
sdhci_pre_dma_transfer
(
host
,
data
,
COOKIE_MAPPED
);
ret
=
sdhci_adma_table_pre
(
host
,
data
);
if
(
ret
)
{
if
(
sg_cnt
<=
0
)
{
/*
/*
* This only happens when someone fed
* This only happens when someone fed
* us an invalid request.
* us an invalid request.
*/
*/
WARN_ON
(
1
);
WARN_ON
(
1
);
host
->
flags
&=
~
SDHCI_REQ_USE_DMA
;
host
->
flags
&=
~
SDHCI_REQ_USE_DMA
;
}
else
{
}
else
if
(
host
->
flags
&
SDHCI_USE_ADMA
)
{
sdhci_writel
(
host
,
host
->
adma_addr
,
sdhci_adma_table_pre
(
host
,
data
,
sg_cnt
);
SDHCI_ADMA_ADDRESS
);
sdhci_writel
(
host
,
host
->
adma_addr
,
SDHCI_ADMA_ADDRESS
);
if
(
host
->
flags
&
SDHCI_USE_64_BIT_DMA
)
if
(
host
->
flags
&
SDHCI_USE_64_BIT_DMA
)
sdhci_writel
(
host
,
sdhci_writel
(
host
,
(
u64
)
host
->
adma_addr
>>
32
,
(
u64
)
host
->
adma_addr
>>
32
,
SDHCI_ADMA_ADDRESS_HI
);
SDHCI_ADMA_ADDRESS_HI
);
}
}
else
{
int
sg_cnt
;
sg_cnt
=
sdhci_pre_dma_transfer
(
host
,
data
,
NULL
);
if
(
sg_cnt
==
0
)
{
/*
* This only happens when someone fed
* us an invalid request.
*/
WARN_ON
(
1
);
host
->
flags
&=
~
SDHCI_REQ_USE_DMA
;
}
else
{
}
else
{
WARN_ON
(
sg_cnt
!=
1
);
WARN_ON
(
sg_cnt
!=
1
);
sdhci_writel
(
host
,
sg_dma_address
(
data
->
sg
),
sdhci_writel
(
host
,
sg_dma_address
(
data
->
sg
),
SDHCI_DMA_ADDRESS
);
SDHCI_DMA_ADDRESS
);
}
}
}
}
}
/*
/*
* Always adjust the DMA selection as some controllers
* Always adjust the DMA selection as some controllers
...
@@ -914,6 +896,13 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
...
@@ -914,6 +896,13 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
sdhci_writew
(
host
,
data
->
blocks
,
SDHCI_BLOCK_COUNT
);
sdhci_writew
(
host
,
data
->
blocks
,
SDHCI_BLOCK_COUNT
);
}
}
static
inline
bool
sdhci_auto_cmd12
(
struct
sdhci_host
*
host
,
struct
mmc_request
*
mrq
)
{
return
!
mrq
->
sbc
&&
(
host
->
flags
&
SDHCI_AUTO_CMD12
)
&&
!
mrq
->
cap_cmd_during_tfr
;
}
static
void
sdhci_set_transfer_mode
(
struct
sdhci_host
*
host
,
static
void
sdhci_set_transfer_mode
(
struct
sdhci_host
*
host
,
struct
mmc_command
*
cmd
)
struct
mmc_command
*
cmd
)
{
{
...
@@ -944,11 +933,12 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
...
@@ -944,11 +933,12 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
* If we are sending CMD23, CMD12 never gets sent
* If we are sending CMD23, CMD12 never gets sent
* on successful completion (so no Auto-CMD12).
* on successful completion (so no Auto-CMD12).
*/
*/
if
(
!
host
->
mrq
->
sbc
&&
(
host
->
flags
&
SDHCI_AUTO_CMD12
))
if
(
sdhci_auto_cmd12
(
host
,
cmd
->
mrq
)
&&
(
cmd
->
opcode
!=
SD_IO_RW_EXTENDED
))
mode
|=
SDHCI_TRNS_AUTO_CMD12
;
mode
|=
SDHCI_TRNS_AUTO_CMD12
;
else
if
(
host
->
mrq
->
sbc
&&
(
host
->
flags
&
SDHCI_AUTO_CMD23
))
{
else
if
(
cmd
->
mrq
->
sbc
&&
(
host
->
flags
&
SDHCI_AUTO_CMD23
))
{
mode
|=
SDHCI_TRNS_AUTO_CMD23
;
mode
|=
SDHCI_TRNS_AUTO_CMD23
;
sdhci_writel
(
host
,
host
->
mrq
->
sbc
->
arg
,
SDHCI_ARGUMENT2
);
sdhci_writel
(
host
,
cmd
->
mrq
->
sbc
->
arg
,
SDHCI_ARGUMENT2
);
}
}
}
}
...
@@ -960,27 +950,68 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
...
@@ -960,27 +950,68 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
sdhci_writew
(
host
,
mode
,
SDHCI_TRANSFER_MODE
);
sdhci_writew
(
host
,
mode
,
SDHCI_TRANSFER_MODE
);
}
}
static
void
sdhci_finish_data
(
struct
sdhci_host
*
host
)
static
bool
sdhci_needs_reset
(
struct
sdhci_host
*
host
,
struct
mmc_request
*
mrq
)
{
{
struct
mmc_data
*
data
;
return
(
!
(
host
->
flags
&
SDHCI_DEVICE_DEAD
)
&&
((
mrq
->
cmd
&&
mrq
->
cmd
->
error
)
||
(
mrq
->
sbc
&&
mrq
->
sbc
->
error
)
||
(
mrq
->
data
&&
((
mrq
->
data
->
error
&&
!
mrq
->
data
->
stop
)
||
(
mrq
->
data
->
stop
&&
mrq
->
data
->
stop
->
error
)))
||
(
host
->
quirks
&
SDHCI_QUIRK_RESET_AFTER_REQUEST
)));
}
BUG_ON
(
!
host
->
data
);
static
void
__sdhci_finish_mrq
(
struct
sdhci_host
*
host
,
struct
mmc_request
*
mrq
)
{
int
i
;
data
=
host
->
data
;
for
(
i
=
0
;
i
<
SDHCI_MAX_MRQS
;
i
++
)
{
host
->
data
=
NULL
;
if
(
host
->
mrqs_done
[
i
]
==
mrq
)
{
WARN_ON
(
1
);
return
;
}
}
if
(
host
->
flags
&
SDHCI_REQ_USE_DMA
)
{
for
(
i
=
0
;
i
<
SDHCI_MAX_MRQS
;
i
++
)
{
if
(
host
->
flags
&
SDHCI_USE_ADMA
)
if
(
!
host
->
mrqs_done
[
i
])
{
sdhci_adma_table_post
(
host
,
data
);
host
->
mrqs_done
[
i
]
=
mrq
;
else
{
break
;
if
(
!
data
->
host_cookie
)
dma_unmap_sg
(
mmc_dev
(
host
->
mmc
),
data
->
sg
,
data
->
sg_len
,
(
data
->
flags
&
MMC_DATA_READ
)
?
DMA_FROM_DEVICE
:
DMA_TO_DEVICE
);
}
}
}
}
WARN_ON
(
i
>=
SDHCI_MAX_MRQS
);
tasklet_schedule
(
&
host
->
finish_tasklet
);
}
static
void
sdhci_finish_mrq
(
struct
sdhci_host
*
host
,
struct
mmc_request
*
mrq
)
{
if
(
host
->
cmd
&&
host
->
cmd
->
mrq
==
mrq
)
host
->
cmd
=
NULL
;
if
(
host
->
data_cmd
&&
host
->
data_cmd
->
mrq
==
mrq
)
host
->
data_cmd
=
NULL
;
if
(
host
->
data
&&
host
->
data
->
mrq
==
mrq
)
host
->
data
=
NULL
;
if
(
sdhci_needs_reset
(
host
,
mrq
))
host
->
pending_reset
=
true
;
__sdhci_finish_mrq
(
host
,
mrq
);
}
static
void
sdhci_finish_data
(
struct
sdhci_host
*
host
)
{
struct
mmc_command
*
data_cmd
=
host
->
data_cmd
;
struct
mmc_data
*
data
=
host
->
data
;
host
->
data
=
NULL
;
host
->
data_cmd
=
NULL
;
if
((
host
->
flags
&
(
SDHCI_REQ_USE_DMA
|
SDHCI_USE_ADMA
))
==
(
SDHCI_REQ_USE_DMA
|
SDHCI_USE_ADMA
))
sdhci_adma_table_post
(
host
,
data
);
/*
/*
* The specification states that the block count register must
* The specification states that the block count register must
* be updated, but it does not specify at what point in the
* be updated, but it does not specify at what point in the
...
@@ -1000,20 +1031,50 @@ static void sdhci_finish_data(struct sdhci_host *host)
...
@@ -1000,20 +1031,50 @@ static void sdhci_finish_data(struct sdhci_host *host)
*/
*/
if
(
data
->
stop
&&
if
(
data
->
stop
&&
(
data
->
error
||
(
data
->
error
||
!
host
->
mrq
->
sbc
))
{
!
data
->
mrq
->
sbc
))
{
/*
/*
* The controller needs a reset of internal state machines
* The controller needs a reset of internal state machines
* upon error conditions.
* upon error conditions.
*/
*/
if
(
data
->
error
)
{
if
(
data
->
error
)
{
if
(
!
host
->
cmd
||
host
->
cmd
==
data_cmd
)
sdhci_do_reset
(
host
,
SDHCI_RESET_CMD
);
sdhci_do_reset
(
host
,
SDHCI_RESET_CMD
);
sdhci_do_reset
(
host
,
SDHCI_RESET_DATA
);
sdhci_do_reset
(
host
,
SDHCI_RESET_DATA
);
}
}
/*
* 'cap_cmd_during_tfr' request must not use the command line
* after mmc_command_done() has been called. It is upper layer's
* responsibility to send the stop command if required.
*/
if
(
data
->
mrq
->
cap_cmd_during_tfr
)
{
sdhci_finish_mrq
(
host
,
data
->
mrq
);
}
else
{
/* Avoid triggering warning in sdhci_send_command() */
host
->
cmd
=
NULL
;
sdhci_send_command
(
host
,
data
->
stop
);
sdhci_send_command
(
host
,
data
->
stop
);
}
else
}
tasklet_schedule
(
&
host
->
finish_tasklet
);
}
else
{
sdhci_finish_mrq
(
host
,
data
->
mrq
);
}
}
static
void
sdhci_mod_timer
(
struct
sdhci_host
*
host
,
struct
mmc_request
*
mrq
,
unsigned
long
timeout
)
{
if
(
sdhci_data_line_cmd
(
mrq
->
cmd
))
mod_timer
(
&
host
->
data_timer
,
timeout
);
else
mod_timer
(
&
host
->
timer
,
timeout
);
}
static
void
sdhci_del_timer
(
struct
sdhci_host
*
host
,
struct
mmc_request
*
mrq
)
{
if
(
sdhci_data_line_cmd
(
mrq
->
cmd
))
del_timer
(
&
host
->
data_timer
);
else
del_timer
(
&
host
->
timer
);
}
}
void
sdhci_send_command
(
struct
sdhci_host
*
host
,
struct
mmc_command
*
cmd
)
void
sdhci_send_command
(
struct
sdhci_host
*
host
,
struct
mmc_command
*
cmd
)
...
@@ -1024,25 +1085,32 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
...
@@ -1024,25 +1085,32 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
WARN_ON
(
host
->
cmd
);
WARN_ON
(
host
->
cmd
);
/* Initially, a command has no error */
cmd
->
error
=
0
;
if
((
host
->
quirks2
&
SDHCI_QUIRK2_STOP_WITH_TC
)
&&
cmd
->
opcode
==
MMC_STOP_TRANSMISSION
)
cmd
->
flags
|=
MMC_RSP_BUSY
;
/* Wait max 10 ms */
/* Wait max 10 ms */
timeout
=
10
;
timeout
=
10
;
mask
=
SDHCI_CMD_INHIBIT
;
mask
=
SDHCI_CMD_INHIBIT
;
if
(
(
cmd
->
data
!=
NULL
)
||
(
cmd
->
flags
&
MMC_RSP_BUSY
))
if
(
sdhci_data_line_cmd
(
cmd
))
mask
|=
SDHCI_DATA_INHIBIT
;
mask
|=
SDHCI_DATA_INHIBIT
;
/* We shouldn't wait for data inihibit for stop commands, even
/* We shouldn't wait for data inihibit for stop commands, even
though they might use busy signaling */
though they might use busy signaling */
if
(
host
->
mrq
->
data
&&
(
cmd
==
host
->
mrq
->
data
->
stop
))
if
(
cmd
->
mrq
->
data
&&
(
cmd
==
cmd
->
mrq
->
data
->
stop
))
mask
&=
~
SDHCI_DATA_INHIBIT
;
mask
&=
~
SDHCI_DATA_INHIBIT
;
while
(
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
)
&
mask
)
{
while
(
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
)
&
mask
)
{
if
(
timeout
==
0
)
{
if
(
timeout
==
0
)
{
pr_err
(
"%s: Controller never released
"
pr_err
(
"%s: Controller never released
inhibit bit(s).
\n
"
,
"inhibit bit(s).
\n
"
,
mmc_hostname
(
host
->
mmc
));
mmc_hostname
(
host
->
mmc
));
sdhci_dumpregs
(
host
);
sdhci_dumpregs
(
host
);
cmd
->
error
=
-
EIO
;
cmd
->
error
=
-
EIO
;
tasklet_schedule
(
&
host
->
finish_tasklet
);
sdhci_finish_mrq
(
host
,
cmd
->
mrq
);
return
;
return
;
}
}
timeout
--
;
timeout
--
;
...
@@ -1054,10 +1122,13 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
...
@@ -1054,10 +1122,13 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
timeout
+=
DIV_ROUND_UP
(
cmd
->
busy_timeout
,
1000
)
*
HZ
+
HZ
;
timeout
+=
DIV_ROUND_UP
(
cmd
->
busy_timeout
,
1000
)
*
HZ
+
HZ
;
else
else
timeout
+=
10
*
HZ
;
timeout
+=
10
*
HZ
;
mod_timer
(
&
host
->
timer
,
timeout
);
sdhci_mod_timer
(
host
,
cmd
->
mrq
,
timeout
);
host
->
cmd
=
cmd
;
host
->
cmd
=
cmd
;
host
->
busy_handle
=
0
;
if
(
sdhci_data_line_cmd
(
cmd
))
{
WARN_ON
(
host
->
data_cmd
);
host
->
data_cmd
=
cmd
;
}
sdhci_prepare_data
(
host
,
cmd
);
sdhci_prepare_data
(
host
,
cmd
);
...
@@ -1069,7 +1140,7 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
...
@@ -1069,7 +1140,7 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
pr_err
(
"%s: Unsupported response type!
\n
"
,
pr_err
(
"%s: Unsupported response type!
\n
"
,
mmc_hostname
(
host
->
mmc
));
mmc_hostname
(
host
->
mmc
));
cmd
->
error
=
-
EINVAL
;
cmd
->
error
=
-
EINVAL
;
tasklet_schedule
(
&
host
->
finish_tasklet
);
sdhci_finish_mrq
(
host
,
cmd
->
mrq
);
return
;
return
;
}
}
...
@@ -1098,42 +1169,61 @@ EXPORT_SYMBOL_GPL(sdhci_send_command);
...
@@ -1098,42 +1169,61 @@ EXPORT_SYMBOL_GPL(sdhci_send_command);
static
void
sdhci_finish_command
(
struct
sdhci_host
*
host
)
static
void
sdhci_finish_command
(
struct
sdhci_host
*
host
)
{
{
struct
mmc_command
*
cmd
=
host
->
cmd
;
int
i
;
int
i
;
BUG_ON
(
host
->
cmd
==
NULL
)
;
host
->
cmd
=
NULL
;
if
(
host
->
cmd
->
flags
&
MMC_RSP_PRESENT
)
{
if
(
cmd
->
flags
&
MMC_RSP_PRESENT
)
{
if
(
host
->
cmd
->
flags
&
MMC_RSP_136
)
{
if
(
cmd
->
flags
&
MMC_RSP_136
)
{
/* CRC is stripped so we need to do some shifting. */
/* CRC is stripped so we need to do some shifting. */
for
(
i
=
0
;
i
<
4
;
i
++
)
{
for
(
i
=
0
;
i
<
4
;
i
++
)
{
host
->
cmd
->
resp
[
i
]
=
sdhci_readl
(
host
,
cmd
->
resp
[
i
]
=
sdhci_readl
(
host
,
SDHCI_RESPONSE
+
(
3
-
i
)
*
4
)
<<
8
;
SDHCI_RESPONSE
+
(
3
-
i
)
*
4
)
<<
8
;
if
(
i
!=
3
)
if
(
i
!=
3
)
host
->
cmd
->
resp
[
i
]
|=
cmd
->
resp
[
i
]
|=
sdhci_readb
(
host
,
sdhci_readb
(
host
,
SDHCI_RESPONSE
+
(
3
-
i
)
*
4
-
1
);
SDHCI_RESPONSE
+
(
3
-
i
)
*
4
-
1
);
}
}
}
else
{
}
else
{
host
->
cmd
->
resp
[
0
]
=
sdhci_readl
(
host
,
SDHCI_RESPONSE
);
cmd
->
resp
[
0
]
=
sdhci_readl
(
host
,
SDHCI_RESPONSE
);
}
}
}
}
host
->
cmd
->
error
=
0
;
if
(
cmd
->
mrq
->
cap_cmd_during_tfr
&&
cmd
==
cmd
->
mrq
->
cmd
)
mmc_command_done
(
host
->
mmc
,
cmd
->
mrq
);
/*
* The host can send and interrupt when the busy state has
* ended, allowing us to wait without wasting CPU cycles.
* The busy signal uses DAT0 so this is similar to waiting
* for data to complete.
*
* Note: The 1.0 specification is a bit ambiguous about this
* feature so there might be some problems with older
* controllers.
*/
if
(
cmd
->
flags
&
MMC_RSP_BUSY
)
{
if
(
cmd
->
data
)
{
DBG
(
"Cannot wait for busy signal when also doing a data transfer"
);
}
else
if
(
!
(
host
->
quirks
&
SDHCI_QUIRK_NO_BUSY_IRQ
)
&&
cmd
==
host
->
data_cmd
)
{
/* Command complete before busy is ended */
return
;
}
}
/* Finished CMD23, now send actual command. */
/* Finished CMD23, now send actual command. */
if
(
host
->
cmd
==
host
->
mrq
->
sbc
)
{
if
(
cmd
==
cmd
->
mrq
->
sbc
)
{
host
->
cmd
=
NULL
;
sdhci_send_command
(
host
,
cmd
->
mrq
->
cmd
);
sdhci_send_command
(
host
,
host
->
mrq
->
cmd
);
}
else
{
}
else
{
/* Processed actual command. */
/* Processed actual command. */
if
(
host
->
data
&&
host
->
data_early
)
if
(
host
->
data
&&
host
->
data_early
)
sdhci_finish_data
(
host
);
sdhci_finish_data
(
host
);
if
(
!
host
->
cmd
->
data
)
if
(
!
cmd
->
data
)
tasklet_schedule
(
&
host
->
finish_tasklet
);
sdhci_finish_mrq
(
host
,
cmd
->
mrq
);
host
->
cmd
=
NULL
;
}
}
}
}
...
@@ -1156,6 +1246,7 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
...
@@ -1156,6 +1246,7 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
preset
=
sdhci_readw
(
host
,
SDHCI_PRESET_FOR_SDR104
);
preset
=
sdhci_readw
(
host
,
SDHCI_PRESET_FOR_SDR104
);
break
;
break
;
case
MMC_TIMING_UHS_DDR50
:
case
MMC_TIMING_UHS_DDR50
:
case
MMC_TIMING_MMC_DDR52
:
preset
=
sdhci_readw
(
host
,
SDHCI_PRESET_FOR_DDR50
);
preset
=
sdhci_readw
(
host
,
SDHCI_PRESET_FOR_DDR50
);
break
;
break
;
case
MMC_TIMING_MMC_HS400
:
case
MMC_TIMING_MMC_HS400
:
...
@@ -1170,19 +1261,13 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
...
@@ -1170,19 +1261,13 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
return
preset
;
return
preset
;
}
}
void
sdhci_set_clock
(
struct
sdhci_host
*
host
,
unsigned
int
clock
)
u16
sdhci_calc_clk
(
struct
sdhci_host
*
host
,
unsigned
int
clock
,
unsigned
int
*
actual_clock
)
{
{
int
div
=
0
;
/* Initialized for compiler warning */
int
div
=
0
;
/* Initialized for compiler warning */
int
real_div
=
div
,
clk_mul
=
1
;
int
real_div
=
div
,
clk_mul
=
1
;
u16
clk
=
0
;
u16
clk
=
0
;
unsigned
long
timeout
;
bool
switch_base_clk
=
false
;
host
->
mmc
->
actual_clock
=
0
;
sdhci_writew
(
host
,
0
,
SDHCI_CLOCK_CONTROL
);
if
(
clock
==
0
)
return
;
if
(
host
->
version
>=
SDHCI_SPEC_300
)
{
if
(
host
->
version
>=
SDHCI_SPEC_300
)
{
if
(
host
->
preset_enabled
)
{
if
(
host
->
preset_enabled
)
{
...
@@ -1213,6 +1298,7 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
...
@@ -1213,6 +1298,7 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
<=
clock
)
<=
clock
)
break
;
break
;
}
}
if
((
host
->
max_clk
*
host
->
clk_mul
/
div
)
<=
clock
)
{
/*
/*
* Set Programmable Clock Mode in the Clock
* Set Programmable Clock Mode in the Clock
* Control register.
* Control register.
...
@@ -1222,6 +1308,15 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
...
@@ -1222,6 +1308,15 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
clk_mul
=
host
->
clk_mul
;
clk_mul
=
host
->
clk_mul
;
div
--
;
div
--
;
}
else
{
}
else
{
/*
* Divisor can be too small to reach clock
* speed requirement. Then use the base clock.
*/
switch_base_clk
=
true
;
}
}
if
(
!
host
->
clk_mul
||
switch_base_clk
)
{
/* Version 3.00 divisors must be a multiple of 2. */
/* Version 3.00 divisors must be a multiple of 2. */
if
(
host
->
max_clk
<=
clock
)
if
(
host
->
max_clk
<=
clock
)
div
=
1
;
div
=
1
;
...
@@ -1250,10 +1345,29 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
...
@@ -1250,10 +1345,29 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
clock_set:
clock_set:
if
(
real_div
)
if
(
real_div
)
host
->
mmc
->
actual_clock
=
(
host
->
max_clk
*
clk_mul
)
/
real_div
;
*
actual_clock
=
(
host
->
max_clk
*
clk_mul
)
/
real_div
;
clk
|=
(
div
&
SDHCI_DIV_MASK
)
<<
SDHCI_DIVIDER_SHIFT
;
clk
|=
(
div
&
SDHCI_DIV_MASK
)
<<
SDHCI_DIVIDER_SHIFT
;
clk
|=
((
div
&
SDHCI_DIV_HI_MASK
)
>>
SDHCI_DIV_MASK_LEN
)
clk
|=
((
div
&
SDHCI_DIV_HI_MASK
)
>>
SDHCI_DIV_MASK_LEN
)
<<
SDHCI_DIVIDER_HI_SHIFT
;
<<
SDHCI_DIVIDER_HI_SHIFT
;
return
clk
;
}
EXPORT_SYMBOL_GPL
(
sdhci_calc_clk
);
void
sdhci_set_clock
(
struct
sdhci_host
*
host
,
unsigned
int
clock
)
{
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
);
clk
|=
SDHCI_CLOCK_INT_EN
;
clk
|=
SDHCI_CLOCK_INT_EN
;
sdhci_writew
(
host
,
clk
,
SDHCI_CLOCK_CONTROL
);
sdhci_writew
(
host
,
clk
,
SDHCI_CLOCK_CONTROL
);
...
@@ -1262,8 +1376,8 @@ clock_set:
...
@@ -1262,8 +1376,8 @@ clock_set:
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
(
timeout
==
0
)
{
pr_err
(
"%s: Internal clock never
"
pr_err
(
"%s: Internal clock never
stabilised.
\n
"
,
"stabilised.
\n
"
,
mmc_hostname
(
host
->
mmc
));
mmc_hostname
(
host
->
mmc
));
sdhci_dumpregs
(
host
);
sdhci_dumpregs
(
host
);
return
;
return
;
}
}
...
@@ -1276,13 +1390,11 @@ clock_set:
...
@@ -1276,13 +1390,11 @@ clock_set:
}
}
EXPORT_SYMBOL_GPL
(
sdhci_set_clock
);
EXPORT_SYMBOL_GPL
(
sdhci_set_clock
);
static
void
sdhci_set_power
(
struct
sdhci_host
*
host
,
unsigned
char
mode
,
static
void
sdhci_set_power
_reg
(
struct
sdhci_host
*
host
,
unsigned
char
mode
,
unsigned
short
vdd
)
unsigned
short
vdd
)
{
{
struct
mmc_host
*
mmc
=
host
->
mmc
;
struct
mmc_host
*
mmc
=
host
->
mmc
;
u8
pwr
=
0
;
if
(
!
IS_ERR
(
mmc
->
supply
.
vmmc
))
{
spin_unlock_irq
(
&
host
->
lock
);
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
);
spin_lock_irq
(
&
host
->
lock
);
...
@@ -1291,9 +1403,12 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
...
@@ -1291,9 +1403,12 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
sdhci_writeb
(
host
,
SDHCI_POWER_ON
,
SDHCI_POWER_CONTROL
);
sdhci_writeb
(
host
,
SDHCI_POWER_ON
,
SDHCI_POWER_CONTROL
);
else
else
sdhci_writeb
(
host
,
0
,
SDHCI_POWER_CONTROL
);
sdhci_writeb
(
host
,
0
,
SDHCI_POWER_CONTROL
);
}
return
;
void
sdhci_set_power_noreg
(
struct
sdhci_host
*
host
,
unsigned
char
mode
,
}
unsigned
short
vdd
)
{
u8
pwr
=
0
;
if
(
mode
!=
MMC_POWER_OFF
)
{
if
(
mode
!=
MMC_POWER_OFF
)
{
switch
(
1
<<
vdd
)
{
switch
(
1
<<
vdd
)
{
...
@@ -1309,7 +1424,9 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
...
@@ -1309,7 +1424,9 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
pwr
=
SDHCI_POWER_330
;
pwr
=
SDHCI_POWER_330
;
break
;
break
;
default:
default:
BUG
();
WARN
(
1
,
"%s: Invalid vdd %#x
\n
"
,
mmc_hostname
(
host
->
mmc
),
vdd
);
break
;
}
}
}
}
...
@@ -1322,7 +1439,6 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
...
@@ -1322,7 +1439,6 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
sdhci_writeb
(
host
,
0
,
SDHCI_POWER_CONTROL
);
sdhci_writeb
(
host
,
0
,
SDHCI_POWER_CONTROL
);
if
(
host
->
quirks2
&
SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON
)
if
(
host
->
quirks2
&
SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON
)
sdhci_runtime_pm_bus_off
(
host
);
sdhci_runtime_pm_bus_off
(
host
);
vdd
=
0
;
}
else
{
}
else
{
/*
/*
* Spec says that we should clear the power reg before setting
* Spec says that we should clear the power reg before setting
...
@@ -1354,6 +1470,17 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
...
@@ -1354,6 +1470,17 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
mdelay
(
10
);
mdelay
(
10
);
}
}
}
}
EXPORT_SYMBOL_GPL
(
sdhci_set_power_noreg
);
void
sdhci_set_power
(
struct
sdhci_host
*
host
,
unsigned
char
mode
,
unsigned
short
vdd
)
{
if
(
IS_ERR
(
host
->
mmc
->
supply
.
vmmc
))
sdhci_set_power_noreg
(
host
,
mode
,
vdd
);
else
sdhci_set_power_reg
(
host
,
mode
,
vdd
);
}
EXPORT_SYMBOL_GPL
(
sdhci_set_power
);
/*****************************************************************************\
/*****************************************************************************\
* *
* *
...
@@ -1366,42 +1493,28 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
...
@@ -1366,42 +1493,28 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
struct
sdhci_host
*
host
;
struct
sdhci_host
*
host
;
int
present
;
int
present
;
unsigned
long
flags
;
unsigned
long
flags
;
u32
tuning_opcode
;
host
=
mmc_priv
(
mmc
);
host
=
mmc_priv
(
mmc
);
sdhci_runtime_pm_get
(
host
);
/* Firstly check card presence */
present
=
mmc
->
ops
->
get_cd
(
mmc
);
present
=
mmc_gpio_get_cd
(
host
->
mmc
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
WARN_ON
(
host
->
mrq
!=
NULL
);
sdhci_led_activate
(
host
);
#ifndef SDHCI_USE_LEDS_CLASS
sdhci_activate_led
(
host
);
#endif
/*
/*
* Ensure we don't send the STOP for non-SET_BLOCK_COUNTED
* Ensure we don't send the STOP for non-SET_BLOCK_COUNTED
* requests if Auto-CMD12 is enabled.
* requests if Auto-CMD12 is enabled.
*/
*/
if
(
!
mrq
->
sbc
&&
(
host
->
flags
&
SDHCI_AUTO_CMD12
))
{
if
(
sdhci_auto_cmd12
(
host
,
mrq
))
{
if
(
mrq
->
stop
)
{
if
(
mrq
->
stop
)
{
mrq
->
data
->
stop
=
NULL
;
mrq
->
data
->
stop
=
NULL
;
mrq
->
stop
=
NULL
;
mrq
->
stop
=
NULL
;
}
}
}
}
host
->
mrq
=
mrq
;
// Elphel: returned old code - investigate and remove later
/*
* Firstly check card presence from cd-gpio. The return could
* be one of the following possibilities:
* negative: cd-gpio is not available
* zero: cd-gpio is used, and card is removed
* one: cd-gpio is used, and card is present
*/
if
(
present
<
0
)
{
if
(
present
<
0
)
{
/* If polling, assume that the card is always present. */
/* If polling, assume that the card is always present. */
if
(
host
->
quirks
&
SDHCI_QUIRK_BROKEN_CARD_DETECTION
)
if
(
host
->
quirks
&
SDHCI_QUIRK_BROKEN_CARD_DETECTION
)
...
@@ -1411,52 +1524,10 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
...
@@ -1411,52 +1524,10 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
SDHCI_ANY_PRESENT
;
SDHCI_ANY_PRESENT
;
}
}
/*oleg's debug
if (!present){
pr_err("sdhci card request: card not present?\n");
present = 1;
}else{
pr_err("sdhci card request: CARD IS PRESENT: 0x%08x\n",present);
}
*/
if
(
!
present
||
host
->
flags
&
SDHCI_DEVICE_DEAD
)
{
if
(
!
present
||
host
->
flags
&
SDHCI_DEVICE_DEAD
)
{
mrq
->
cmd
->
error
=
-
ENOMEDIUM
;
host
->
mrq
->
cmd
->
error
=
-
ENOMEDIUM
;
sdhci_finish_mrq
(
host
,
mrq
);
tasklet_schedule
(
&
host
->
finish_tasklet
);
}
else
{
}
else
{
u32
present_state
;
present_state
=
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
);
/*
* Check if the re-tuning timer has already expired and there
* is no on-going data transfer and DAT0 is not busy. If so,
* we need to execute tuning procedure before sending command.
*/
if
((
host
->
flags
&
SDHCI_NEEDS_RETUNING
)
&&
!
(
present_state
&
(
SDHCI_DOING_WRITE
|
SDHCI_DOING_READ
))
&&
(
present_state
&
SDHCI_DATA_0_LVL_MASK
))
{
if
(
mmc
->
card
)
{
/* eMMC uses cmd21 but sd and sdio use cmd19 */
tuning_opcode
=
mmc
->
card
->
type
==
MMC_TYPE_MMC
?
MMC_SEND_TUNING_BLOCK_HS200
:
MMC_SEND_TUNING_BLOCK
;
/* Here we need to set the host->mrq to NULL,
* in case the pending finish_tasklet
* finishes it incorrectly.
*/
host
->
mrq
=
NULL
;
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
sdhci_execute_tuning
(
mmc
,
tuning_opcode
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
/* Restore original mmc_request structure */
host
->
mrq
=
mrq
;
}
}
if
(
mrq
->
sbc
&&
!
(
host
->
flags
&
SDHCI_AUTO_CMD23
))
if
(
mrq
->
sbc
&&
!
(
host
->
flags
&
SDHCI_AUTO_CMD23
))
sdhci_send_command
(
host
,
mrq
->
sbc
);
sdhci_send_command
(
host
,
mrq
->
sbc
);
else
else
...
@@ -1513,11 +1584,11 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
...
@@ -1513,11 +1584,11 @@ 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_
do_set_ios
(
struct
sdhci_host
*
host
,
struct
mmc_ios
*
ios
)
static
void
sdhci_
set_ios
(
struct
mmc_host
*
mmc
,
struct
mmc_ios
*
ios
)
{
{
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
unsigned
long
flags
;
unsigned
long
flags
;
u8
ctrl
;
u8
ctrl
;
struct
mmc_host
*
mmc
=
host
->
mmc
;
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
...
@@ -1560,6 +1631,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
...
@@ -1560,6 +1631,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
}
}
}
}
if
(
host
->
ops
->
set_power
)
host
->
ops
->
set_power
(
host
,
ios
->
power_mode
,
ios
->
vdd
);
else
sdhci_set_power
(
host
,
ios
->
power_mode
,
ios
->
vdd
);
sdhci_set_power
(
host
,
ios
->
power_mode
,
ios
->
vdd
);
if
(
host
->
ops
->
platform_send_init_74_clocks
)
if
(
host
->
ops
->
platform_send_init_74_clocks
)
...
@@ -1599,8 +1673,17 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
...
@@ -1599,8 +1673,17 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
ctrl_2
&=
~
SDHCI_CTRL_DRV_TYPE_MASK
;
ctrl_2
&=
~
SDHCI_CTRL_DRV_TYPE_MASK
;
if
(
ios
->
drv_type
==
MMC_SET_DRIVER_TYPE_A
)
if
(
ios
->
drv_type
==
MMC_SET_DRIVER_TYPE_A
)
ctrl_2
|=
SDHCI_CTRL_DRV_TYPE_A
;
ctrl_2
|=
SDHCI_CTRL_DRV_TYPE_A
;
else
if
(
ios
->
drv_type
==
MMC_SET_DRIVER_TYPE_B
)
ctrl_2
|=
SDHCI_CTRL_DRV_TYPE_B
;
else
if
(
ios
->
drv_type
==
MMC_SET_DRIVER_TYPE_C
)
else
if
(
ios
->
drv_type
==
MMC_SET_DRIVER_TYPE_C
)
ctrl_2
|=
SDHCI_CTRL_DRV_TYPE_C
;
ctrl_2
|=
SDHCI_CTRL_DRV_TYPE_C
;
else
if
(
ios
->
drv_type
==
MMC_SET_DRIVER_TYPE_D
)
ctrl_2
|=
SDHCI_CTRL_DRV_TYPE_D
;
else
{
pr_warn
(
"%s: invalid driver type, default to driver type B
\n
"
,
mmc_hostname
(
mmc
));
ctrl_2
|=
SDHCI_CTRL_DRV_TYPE_B
;
}
sdhci_writew
(
host
,
ctrl_2
,
SDHCI_HOST_CONTROL2
);
sdhci_writew
(
host
,
ctrl_2
,
SDHCI_HOST_CONTROL2
);
}
else
{
}
else
{
...
@@ -1635,7 +1718,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
...
@@ -1635,7 +1718,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
(
ios
->
timing
==
MMC_TIMING_UHS_SDR25
)
||
(
ios
->
timing
==
MMC_TIMING_UHS_SDR25
)
||
(
ios
->
timing
==
MMC_TIMING_UHS_SDR50
)
||
(
ios
->
timing
==
MMC_TIMING_UHS_SDR50
)
||
(
ios
->
timing
==
MMC_TIMING_UHS_SDR104
)
||
(
ios
->
timing
==
MMC_TIMING_UHS_SDR104
)
||
(
ios
->
timing
==
MMC_TIMING_UHS_DDR50
)))
{
(
ios
->
timing
==
MMC_TIMING_UHS_DDR50
)
||
(
ios
->
timing
==
MMC_TIMING_MMC_DDR52
)))
{
u16
preset
;
u16
preset
;
sdhci_enable_preset_value
(
host
,
true
);
sdhci_enable_preset_value
(
host
,
true
);
...
@@ -1661,55 +1745,33 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
...
@@ -1661,55 +1745,33 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
}
}
static
void
sdhci_set_ios
(
struct
mmc_host
*
mmc
,
struct
mmc_ios
*
ios
)
static
int
sdhci_get_cd
(
struct
mmc_host
*
mmc
)
{
{
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
int
gpio_cd
=
mmc_gpio_get_cd
(
mmc
);
sdhci_runtime_pm_get
(
host
);
sdhci_do_set_ios
(
host
,
ios
);
sdhci_runtime_pm_put
(
host
);
}
static
int
sdhci_do_get_cd
(
struct
sdhci_host
*
host
)
{
int
gpio_cd
=
mmc_gpio_get_cd
(
host
->
mmc
);
int
present
;
if
(
host
->
flags
&
SDHCI_DEVICE_DEAD
)
if
(
host
->
flags
&
SDHCI_DEVICE_DEAD
)
return
0
;
return
0
;
/* If polling/nonremovable, assume that the card is always present. */
/* If nonremovable, assume that the card is always present. */
if
((
host
->
quirks
&
SDHCI_QUIRK_BROKEN_CARD_DETECTION
)
||
if
(
!
mmc_card_is_removable
(
host
->
mmc
))
(
host
->
mmc
->
caps
&
MMC_CAP_NONREMOVABLE
))
return
1
;
return
1
;
/* Try slot gpio detect */
/*
if
(
!
IS_ERR_VALUE
(
gpio_cd
))
* Try slot gpio detect, if defined it take precedence
* over build in controller functionality
*/
if
(
gpio_cd
>=
0
)
return
!!
gpio_cd
;
return
!!
gpio_cd
;
present
=
!!
(
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
)
&
SDHCI_ANY_PRESENT
);
/* If polling, assume that the card is always present. */
if
(
host
->
quirks
&
SDHCI_QUIRK_BROKEN_CARD_DETECTION
)
return
1
;
/* oleg's debug
if (!present){
pr_err("sdhci_do_get_cd: card not present\n");
present = 1;
}else{
pr_err("sdhci_do_get_cd: CARD IS PRESENT\n");
}
*/
/* Host native card detect */
/* Host native card detect */
return
present
;
// Elphel
}
//return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
return
!!
(
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
)
&
SDHCI_ANY_PRESENT
);
static
int
sdhci_get_cd
(
struct
mmc_host
*
mmc
)
{
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
int
ret
;
sdhci_runtime_pm_get
(
host
);
ret
=
sdhci_do_get_cd
(
host
);
sdhci_runtime_pm_put
(
host
);
return
ret
;
}
}
static
int
sdhci_check_ro
(
struct
sdhci_host
*
host
)
static
int
sdhci_check_ro
(
struct
sdhci_host
*
host
)
...
@@ -1736,8 +1798,9 @@ static int sdhci_check_ro(struct sdhci_host *host)
...
@@ -1736,8 +1798,9 @@ static int sdhci_check_ro(struct sdhci_host *host)
#define SAMPLE_COUNT 5
#define SAMPLE_COUNT 5
static
int
sdhci_
do_get_ro
(
struct
sdhci_host
*
host
)
static
int
sdhci_
get_ro
(
struct
mmc_host
*
mmc
)
{
{
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
int
i
,
ro_count
;
int
i
,
ro_count
;
if
(
!
(
host
->
quirks
&
SDHCI_QUIRK_UNSTABLE_RO_DETECT
))
if
(
!
(
host
->
quirks
&
SDHCI_QUIRK_UNSTABLE_RO_DETECT
))
...
@@ -1762,17 +1825,6 @@ static void sdhci_hw_reset(struct mmc_host *mmc)
...
@@ -1762,17 +1825,6 @@ static void sdhci_hw_reset(struct mmc_host *mmc)
host
->
ops
->
hw_reset
(
host
);
host
->
ops
->
hw_reset
(
host
);
}
}
static
int
sdhci_get_ro
(
struct
mmc_host
*
mmc
)
{
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
int
ret
;
sdhci_runtime_pm_get
(
host
);
ret
=
sdhci_do_get_ro
(
host
);
sdhci_runtime_pm_put
(
host
);
return
ret
;
}
static
void
sdhci_enable_sdio_irq_nolock
(
struct
sdhci_host
*
host
,
int
enable
)
static
void
sdhci_enable_sdio_irq_nolock
(
struct
sdhci_host
*
host
,
int
enable
)
{
{
if
(
!
(
host
->
flags
&
SDHCI_DEVICE_DEAD
))
{
if
(
!
(
host
->
flags
&
SDHCI_DEVICE_DEAD
))
{
...
@@ -1792,8 +1844,6 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
...
@@ -1792,8 +1844,6 @@ static 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
;
sdhci_runtime_pm_get
(
host
);
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
;
...
@@ -1802,14 +1852,12 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
...
@@ -1802,14 +1852,12 @@ 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
);
sdhci_runtime_pm_put
(
host
);
}
}
static
int
sdhci_
do_start_signal_voltage_switch
(
struct
sdhci_host
*
host
,
static
int
sdhci_
start_signal_voltage_switch
(
struct
mmc_host
*
mmc
,
struct
mmc_ios
*
ios
)
struct
mmc_ios
*
ios
)
{
{
struct
mmc_host
*
mmc
=
host
->
mmc
;
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
)
;
u16
ctrl
;
u16
ctrl
;
int
ret
;
int
ret
;
...
@@ -1824,13 +1872,14 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
...
@@ -1824,13 +1872,14 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
switch
(
ios
->
signal_voltage
)
{
switch
(
ios
->
signal_voltage
)
{
case
MMC_SIGNAL_VOLTAGE_330
:
case
MMC_SIGNAL_VOLTAGE_330
:
if
(
!
(
host
->
flags
&
SDHCI_SIGNALING_330
))
return
-
EINVAL
;
/* Set 1.8V Signal Enable in the Host Control2 register to 0 */
/* Set 1.8V Signal Enable in the Host Control2 register to 0 */
ctrl
&=
~
SDHCI_CTRL_VDD_180
;
ctrl
&=
~
SDHCI_CTRL_VDD_180
;
sdhci_writew
(
host
,
ctrl
,
SDHCI_HOST_CONTROL2
);
sdhci_writew
(
host
,
ctrl
,
SDHCI_HOST_CONTROL2
);
if
(
!
IS_ERR
(
mmc
->
supply
.
vqmmc
))
{
if
(
!
IS_ERR
(
mmc
->
supply
.
vqmmc
))
{
ret
=
regulator_set_voltage
(
mmc
->
supply
.
vqmmc
,
2700000
,
ret
=
mmc_regulator_set_vqmmc
(
mmc
,
ios
);
3600000
);
if
(
ret
)
{
if
(
ret
)
{
pr_warn
(
"%s: Switching to 3.3V signalling voltage failed
\n
"
,
pr_warn
(
"%s: Switching to 3.3V signalling voltage failed
\n
"
,
mmc_hostname
(
mmc
));
mmc_hostname
(
mmc
));
...
@@ -1850,9 +1899,10 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
...
@@ -1850,9 +1899,10 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
return
-
EAGAIN
;
return
-
EAGAIN
;
case
MMC_SIGNAL_VOLTAGE_180
:
case
MMC_SIGNAL_VOLTAGE_180
:
if
(
!
(
host
->
flags
&
SDHCI_SIGNALING_180
))
return
-
EINVAL
;
if
(
!
IS_ERR
(
mmc
->
supply
.
vqmmc
))
{
if
(
!
IS_ERR
(
mmc
->
supply
.
vqmmc
))
{
ret
=
regulator_set_voltage
(
mmc
->
supply
.
vqmmc
,
ret
=
mmc_regulator_set_vqmmc
(
mmc
,
ios
);
1700000
,
1950000
);
if
(
ret
)
{
if
(
ret
)
{
pr_warn
(
"%s: Switching to 1.8V signalling voltage failed
\n
"
,
pr_warn
(
"%s: Switching to 1.8V signalling voltage failed
\n
"
,
mmc_hostname
(
mmc
));
mmc_hostname
(
mmc
));
...
@@ -1881,9 +1931,10 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
...
@@ -1881,9 +1931,10 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
return
-
EAGAIN
;
return
-
EAGAIN
;
case
MMC_SIGNAL_VOLTAGE_120
:
case
MMC_SIGNAL_VOLTAGE_120
:
if
(
!
(
host
->
flags
&
SDHCI_SIGNALING_120
))
return
-
EINVAL
;
if
(
!
IS_ERR
(
mmc
->
supply
.
vqmmc
))
{
if
(
!
IS_ERR
(
mmc
->
supply
.
vqmmc
))
{
ret
=
regulator_set_voltage
(
mmc
->
supply
.
vqmmc
,
1100000
,
ret
=
mmc_regulator_set_vqmmc
(
mmc
,
ios
);
1300000
);
if
(
ret
)
{
if
(
ret
)
{
pr_warn
(
"%s: Switching to 1.2V signalling voltage failed
\n
"
,
pr_warn
(
"%s: Switching to 1.2V signalling voltage failed
\n
"
,
mmc_hostname
(
mmc
));
mmc_hostname
(
mmc
));
...
@@ -1897,31 +1948,15 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
...
@@ -1897,31 +1948,15 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
}
}
}
}
static
int
sdhci_start_signal_voltage_switch
(
struct
mmc_host
*
mmc
,
struct
mmc_ios
*
ios
)
{
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
int
err
;
if
(
host
->
version
<
SDHCI_SPEC_300
)
return
0
;
sdhci_runtime_pm_get
(
host
);
err
=
sdhci_do_start_signal_voltage_switch
(
host
,
ios
);
sdhci_runtime_pm_put
(
host
);
return
err
;
}
static
int
sdhci_card_busy
(
struct
mmc_host
*
mmc
)
static
int
sdhci_card_busy
(
struct
mmc_host
*
mmc
)
{
{
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
u32
present_state
;
u32
present_state
;
sdhci_runtime_pm_get
(
host
);
/* Check whether DAT[0] is 0 */
/* Check whether DAT[3:0] is 0000 */
present_state
=
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
);
present_state
=
sdhci_readl
(
host
,
SDHCI_PRESENT_STATE
);
sdhci_runtime_pm_put
(
host
);
return
!
(
present_state
&
SDHCI_DATA_LVL_MASK
);
return
!
(
present_state
&
SDHCI_DATA_
0_
LVL_MASK
);
}
}
static
int
sdhci_prepare_hs400_tuning
(
struct
mmc_host
*
mmc
,
struct
mmc_ios
*
ios
)
static
int
sdhci_prepare_hs400_tuning
(
struct
mmc_host
*
mmc
,
struct
mmc_ios
*
ios
)
...
@@ -1946,7 +1981,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
...
@@ -1946,7 +1981,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
unsigned
int
tuning_count
=
0
;
unsigned
int
tuning_count
=
0
;
bool
hs400_tuning
;
bool
hs400_tuning
;
sdhci_runtime_pm_get
(
host
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
hs400_tuning
=
host
->
flags
&
SDHCI_HS400_TUNING
;
hs400_tuning
=
host
->
flags
&
SDHCI_HS400_TUNING
;
...
@@ -1956,9 +1990,9 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
...
@@ -1956,9 +1990,9 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
tuning_count
=
host
->
tuning_count
;
tuning_count
=
host
->
tuning_count
;
/*
/*
* The Host Controller needs tuning
only in case of SDR104 mode
* The Host Controller needs tuning
in case of SDR104 and DDR50
*
and for SDR50 mode when Use Tuning for SDR50 is set in the
*
mode, and for SDR50 mode when Use Tuning for SDR50 is set in
* Capabilities register.
*
the
Capabilities register.
* If the Host Controller supports the HS200 mode then the
* If the Host Controller supports the HS200 mode then the
* tuning function has to be executed.
* tuning function has to be executed.
*/
*/
...
@@ -1978,11 +2012,11 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
...
@@ -1978,11 +2012,11 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
break
;
break
;
case
MMC_TIMING_UHS_SDR104
:
case
MMC_TIMING_UHS_SDR104
:
case
MMC_TIMING_UHS_DDR50
:
break
;
break
;
case
MMC_TIMING_UHS_SDR50
:
case
MMC_TIMING_UHS_SDR50
:
if
(
host
->
flags
&
SDHCI_SDR50_NEEDS_TUNING
||
if
(
host
->
flags
&
SDHCI_SDR50_NEEDS_TUNING
)
host
->
flags
&
SDHCI_SDR104_NEEDS_TUNING
)
break
;
break
;
/* FALLTHROUGH */
/* FALLTHROUGH */
...
@@ -1993,7 +2027,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
...
@@ -1993,7 +2027,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
if
(
host
->
ops
->
platform_execute_tuning
)
{
if
(
host
->
ops
->
platform_execute_tuning
)
{
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
err
=
host
->
ops
->
platform_execute_tuning
(
host
,
opcode
);
err
=
host
->
ops
->
platform_execute_tuning
(
host
,
opcode
);
sdhci_runtime_pm_put
(
host
);
return
err
;
return
err
;
}
}
...
@@ -2018,7 +2051,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
...
@@ -2018,7 +2051,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
/*
/*
* Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
* Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
* of loops reaches 40 times
or a timeout of 150ms occurs
.
* of loops reaches 40 times.
*/
*/
do
{
do
{
struct
mmc_command
cmd
=
{
0
};
struct
mmc_command
cmd
=
{
0
};
...
@@ -2029,13 +2062,13 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
...
@@ -2029,13 +2062,13 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
cmd
.
flags
=
MMC_RSP_R1
|
MMC_CMD_ADTC
;
cmd
.
flags
=
MMC_RSP_R1
|
MMC_CMD_ADTC
;
cmd
.
retries
=
0
;
cmd
.
retries
=
0
;
cmd
.
data
=
NULL
;
cmd
.
data
=
NULL
;
cmd
.
mrq
=
&
mrq
;
cmd
.
error
=
0
;
cmd
.
error
=
0
;
if
(
tuning_loop_counter
--
==
0
)
if
(
tuning_loop_counter
--
==
0
)
break
;
break
;
mrq
.
cmd
=
&
cmd
;
mrq
.
cmd
=
&
cmd
;
host
->
mrq
=
&
mrq
;
/*
/*
* In response to CMD19, the card sends 64 bytes of tuning
* In response to CMD19, the card sends 64 bytes of tuning
...
@@ -2065,20 +2098,21 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
...
@@ -2065,20 +2098,21 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
sdhci_send_command
(
host
,
&
cmd
);
sdhci_send_command
(
host
,
&
cmd
);
host
->
cmd
=
NULL
;
host
->
cmd
=
NULL
;
host
->
mrq
=
NULL
;
sdhci_del_timer
(
host
,
&
mrq
)
;
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
/* Wait for Buffer Read Ready interrupt */
/* Wait for Buffer Read Ready interrupt */
wait_event_
interruptible_
timeout
(
host
->
buf_ready_int
,
wait_event_timeout
(
host
->
buf_ready_int
,
(
host
->
tuning_done
==
1
),
(
host
->
tuning_done
==
1
),
msecs_to_jiffies
(
50
));
msecs_to_jiffies
(
50
));
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
if
(
!
host
->
tuning_done
)
{
if
(
!
host
->
tuning_done
)
{
pr_info
(
DRIVER_NAME
": Timeout waiting for "
pr_info
(
DRIVER_NAME
": Timeout waiting for Buffer Read Ready interrupt during tuning procedure, falling back to fixed sampling clock
\n
"
);
"Buffer Read Ready interrupt during tuning "
"procedure, falling back to fixed sampling "
sdhci_do_reset
(
host
,
SDHCI_RESET_CMD
);
"clock
\n
"
);
sdhci_do_reset
(
host
,
SDHCI_RESET_DATA
);
ctrl
=
sdhci_readw
(
host
,
SDHCI_HOST_CONTROL2
);
ctrl
=
sdhci_readw
(
host
,
SDHCI_HOST_CONTROL2
);
ctrl
&=
~
SDHCI_CTRL_TUNED_CLK
;
ctrl
&=
~
SDHCI_CTRL_TUNED_CLK
;
ctrl
&=
~
SDHCI_CTRL_EXEC_TUNING
;
ctrl
&=
~
SDHCI_CTRL_EXEC_TUNING
;
...
@@ -2106,40 +2140,43 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
...
@@ -2106,40 +2140,43 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
sdhci_writew
(
host
,
ctrl
,
SDHCI_HOST_CONTROL2
);
sdhci_writew
(
host
,
ctrl
,
SDHCI_HOST_CONTROL2
);
}
}
if
(
!
(
ctrl
&
SDHCI_CTRL_TUNED_CLK
))
{
if
(
!
(
ctrl
&
SDHCI_CTRL_TUNED_CLK
))
{
pr_info
(
DRIVER_NAME
": Tuning procedure"
pr_info
(
DRIVER_NAME
": Tuning procedure failed, falling back to fixed sampling clock
\n
"
);
" failed, falling back to fixed sampling"
" clock
\n
"
);
err
=
-
EIO
;
err
=
-
EIO
;
}
}
out:
out:
host
->
flags
&=
~
SDHCI_NEEDS_RETUNING
;
if
(
tuning_count
)
{
if
(
tuning_count
)
{
host
->
flags
|=
SDHCI_USING_RETUNING_TIMER
;
mod_timer
(
&
host
->
tuning_timer
,
jiffies
+
tuning_count
*
HZ
);
}
/*
/*
* In case tuning fails, host controllers which support re-tuning can
* In case tuning fails, host controllers which support
* try tuning again at a later time, when the re-tuning timer expires.
* re-tuning can try tuning again at a later time, when the
* So for these controllers, we return 0. Since there might be other
* re-tuning timer expires. So for these controllers, we
* controllers who do not have this capability, we return error for
* return 0. Since there might be other controllers who do not
* them. SDHCI_USING_RETUNING_TIMER means the host is currently using
* have this capability, we return error for them.
* a retuning timer to do the retuning for the card.
*/
*/
if
(
err
&&
(
host
->
flags
&
SDHCI_USING_RETUNING_TIMER
))
err
=
0
;
err
=
0
;
}
host
->
mmc
->
retune_period
=
err
?
0
:
tuning_count
;
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
);
out_unlock:
out_unlock:
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
sdhci_runtime_pm_put
(
host
);
return
err
;
return
err
;
}
}
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
)
{
{
...
@@ -2176,69 +2213,41 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
...
@@ -2176,69 +2213,41 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
struct
mmc_data
*
data
=
mrq
->
data
;
struct
mmc_data
*
data
=
mrq
->
data
;
if
(
host
->
flags
&
SDHCI_REQ_USE_DMA
)
{
if
(
data
->
host_cookie
!=
COOKIE_UNMAPPED
)
if
(
data
->
host_cookie
)
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
?
data
->
flags
&
MMC_DATA_WRITE
?
DMA_TO_DEVICE
:
DMA_FROM_DEVICE
);
DMA_TO_DEVICE
:
DMA_FROM_DEVICE
);
mrq
->
data
->
host_cookie
=
0
;
}
data
->
host_cookie
=
COOKIE_UNMAPPED
;
}
}
static
int
sdhci_pre_dma_transfer
(
struct
sdhci_host
*
host
,
static
void
sdhci_pre_req
(
struct
mmc_host
*
mmc
,
struct
mmc_request
*
mrq
,
struct
mmc_data
*
data
,
bool
is_first_req
)
struct
sdhci_host_next
*
next
)
{
{
int
sg_count
;
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
if
(
!
next
&&
data
->
host_cookie
&&
data
->
host_cookie
!=
host
->
next_data
.
cookie
)
{
pr_debug
(
DRIVER_NAME
"[%s] invalid cookie: %d, next-cookie %d
\n
"
,
__func__
,
data
->
host_cookie
,
host
->
next_data
.
cookie
);
data
->
host_cookie
=
0
;
}
/* Check if next job is already prepared */
if
(
next
||
(
!
next
&&
data
->
host_cookie
!=
host
->
next_data
.
cookie
))
{
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
);
}
else
{
sg_count
=
host
->
next_data
.
sg_count
;
host
->
next_data
.
sg_count
=
0
;
}
if
(
sg_count
==
0
)
return
-
EINVAL
;
if
(
next
)
{
mrq
->
data
->
host_cookie
=
COOKIE_UNMAPPED
;
next
->
sg_count
=
sg_count
;
data
->
host_cookie
=
++
next
->
cookie
<
0
?
1
:
next
->
cookie
;
}
else
host
->
sg_count
=
sg_count
;
return
sg_count
;
if
(
host
->
flags
&
SDHCI_REQ_USE_DMA
)
sdhci_pre_dma_transfer
(
host
,
mrq
->
data
,
COOKIE_PRE_MAPPED
);
}
}
static
void
sdhci_pre_req
(
struct
mmc_host
*
mmc
,
struct
mmc_request
*
mrq
,
static
inline
bool
sdhci_has_requests
(
struct
sdhci_host
*
host
)
bool
is_first_req
)
{
{
struct
sdhci_host
*
host
=
mmc_priv
(
mmc
);
return
host
->
cmd
||
host
->
data_cmd
;
}
if
(
mrq
->
data
->
host_cookie
)
{
static
void
sdhci_error_out_mrqs
(
struct
sdhci_host
*
host
,
int
err
)
mrq
->
data
->
host_cookie
=
0
;
{
return
;
if
(
host
->
data_cmd
)
{
host
->
data_cmd
->
error
=
err
;
sdhci_finish_mrq
(
host
,
host
->
data_cmd
->
mrq
);
}
}
if
(
host
->
flags
&
SDHCI_REQ_USE_DMA
)
if
(
host
->
cmd
)
{
if
(
sdhci_pre_dma_transfer
(
host
,
host
->
cmd
->
error
=
err
;
mrq
->
data
,
sdhci_finish_mrq
(
host
,
host
->
cmd
->
mrq
);
&
host
->
next_data
)
<
0
)
}
mrq
->
data
->
host_cookie
=
0
;
}
}
static
void
sdhci_card_event
(
struct
mmc_host
*
mmc
)
static
void
sdhci_card_event
(
struct
mmc_host
*
mmc
)
...
@@ -2251,12 +2260,12 @@ static void sdhci_card_event(struct mmc_host *mmc)
...
@@ -2251,12 +2260,12 @@ static void sdhci_card_event(struct mmc_host *mmc)
if
(
host
->
ops
->
card_event
)
if
(
host
->
ops
->
card_event
)
host
->
ops
->
card_event
(
host
);
host
->
ops
->
card_event
(
host
);
present
=
sdhci_do_get_cd
(
host
);
present
=
mmc
->
ops
->
get_cd
(
mmc
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
/* Check
host->mrq
first in case we are runtime suspended */
/* Check
sdhci_has_requests()
first in case we are runtime suspended */
if
(
host
->
mrq
&&
!
present
)
{
if
(
sdhci_has_requests
(
host
)
&&
!
present
)
{
pr_err
(
"%s: Card removed during transfer!
\n
"
,
pr_err
(
"%s: Card removed during transfer!
\n
"
,
mmc_hostname
(
host
->
mmc
));
mmc_hostname
(
host
->
mmc
));
pr_err
(
"%s: Resetting controller.
\n
"
,
pr_err
(
"%s: Resetting controller.
\n
"
,
...
@@ -2265,8 +2274,7 @@ static void sdhci_card_event(struct mmc_host *mmc)
...
@@ -2265,8 +2274,7 @@ static void sdhci_card_event(struct mmc_host *mmc)
sdhci_do_reset
(
host
,
SDHCI_RESET_CMD
);
sdhci_do_reset
(
host
,
SDHCI_RESET_CMD
);
sdhci_do_reset
(
host
,
SDHCI_RESET_DATA
);
sdhci_do_reset
(
host
,
SDHCI_RESET_DATA
);
host
->
mrq
->
cmd
->
error
=
-
ENOMEDIUM
;
sdhci_error_out_mrqs
(
host
,
-
ENOMEDIUM
);
tasklet_schedule
(
&
host
->
finish_tasklet
);
}
}
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
...
@@ -2284,6 +2292,7 @@ static const struct mmc_host_ops sdhci_ops = {
...
@@ -2284,6 +2292,7 @@ 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
,
};
};
...
@@ -2294,39 +2303,58 @@ static const struct mmc_host_ops sdhci_ops = {
...
@@ -2294,39 +2303,58 @@ static const struct mmc_host_ops sdhci_ops = {
* *
* *
\*****************************************************************************/
\*****************************************************************************/
static
void
sdhci_tasklet_finish
(
unsigned
long
param
)
static
bool
sdhci_request_done
(
struct
sdhci_host
*
host
)
{
{
struct
sdhci_host
*
host
;
unsigned
long
flags
;
unsigned
long
flags
;
struct
mmc_request
*
mrq
;
struct
mmc_request
*
mrq
;
int
i
;
host
=
(
struct
sdhci_host
*
)
param
;
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
/*
for
(
i
=
0
;
i
<
SDHCI_MAX_MRQS
;
i
++
)
{
* If this tasklet gets rescheduled while running, it will
mrq
=
host
->
mrqs_done
[
i
];
* be run again afterwards but without any active request.
if
(
mrq
)
*/
break
;
if
(
!
host
->
mrq
)
{
}
if
(
!
mrq
)
{
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
return
;
return
true
;
}
}
del_timer
(
&
host
->
timer
);
sdhci_del_timer
(
host
,
mrq
);
mrq
=
host
->
mrq
;
/*
* Always unmap the data buffers if they were mapped by
* sdhci_prepare_data() whenever we finish with a request.
* This avoids leaking DMA mappings on error.
*/
if
(
host
->
flags
&
SDHCI_REQ_USE_DMA
)
{
struct
mmc_data
*
data
=
mrq
->
data
;
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
);
data
->
host_cookie
=
COOKIE_UNMAPPED
;
}
}
/*
/*
* The controller needs a reset of internal state machines
* The controller needs a reset of internal state machines
* upon error conditions.
* upon error conditions.
*/
*/
if
(
!
(
host
->
flags
&
SDHCI_DEVICE_DEAD
)
&&
if
(
sdhci_needs_reset
(
host
,
mrq
))
{
((
mrq
->
cmd
&&
mrq
->
cmd
->
error
)
||
/*
(
mrq
->
sbc
&&
mrq
->
sbc
->
error
)
||
* Do not finish until command and data lines are available for
(
mrq
->
data
&&
((
mrq
->
data
->
error
&&
!
mrq
->
data
->
stop
)
||
* reset. Note there can only be one other mrq, so it cannot
(
mrq
->
data
->
stop
&&
mrq
->
data
->
stop
->
error
)))
||
* also be in mrqs_done, otherwise host->cmd and host->data_cmd
(
host
->
quirks
&
SDHCI_QUIRK_RESET_AFTER_REQUEST
)))
{
* would both be null.
*/
if
(
host
->
cmd
||
host
->
data_cmd
)
{
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
return
true
;
}
/* Some controllers need this kick or reset won't work here */
/* Some controllers need this kick or reset won't work here */
if
(
host
->
quirks
&
SDHCI_QUIRK_CLOCK_BEFORE_RESET
)
if
(
host
->
quirks
&
SDHCI_QUIRK_CLOCK_BEFORE_RESET
)
...
@@ -2337,21 +2365,29 @@ static void sdhci_tasklet_finish(unsigned long param)
...
@@ -2337,21 +2365,29 @@ static void sdhci_tasklet_finish(unsigned long param)
controllers do not like that. */
controllers do not like that. */
sdhci_do_reset
(
host
,
SDHCI_RESET_CMD
);
sdhci_do_reset
(
host
,
SDHCI_RESET_CMD
);
sdhci_do_reset
(
host
,
SDHCI_RESET_DATA
);
sdhci_do_reset
(
host
,
SDHCI_RESET_DATA
);
host
->
pending_reset
=
false
;
}
}
host
->
mrq
=
NULL
;
if
(
!
sdhci_has_requests
(
host
))
host
->
cmd
=
NULL
;
sdhci_led_deactivate
(
host
);
host
->
data
=
NULL
;
#ifndef SDHCI_USE_LEDS_CLASS
host
->
mrqs_done
[
i
]
=
NULL
;
sdhci_deactivate_led
(
host
);
#endif
mmiowb
();
mmiowb
();
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
mmc_request_done
(
host
->
mmc
,
mrq
);
mmc_request_done
(
host
->
mmc
,
mrq
);
sdhci_runtime_pm_put
(
host
);
return
false
;
}
static
void
sdhci_tasklet_finish
(
unsigned
long
param
)
{
struct
sdhci_host
*
host
=
(
struct
sdhci_host
*
)
param
;
while
(
!
sdhci_request_done
(
host
))
;
}
}
static
void
sdhci_timeout_timer
(
unsigned
long
data
)
static
void
sdhci_timeout_timer
(
unsigned
long
data
)
...
@@ -2363,29 +2399,20 @@ static void sdhci_timeout_timer(unsigned long data)
...
@@ -2363,29 +2399,20 @@ static void sdhci_timeout_timer(unsigned long data)
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
if
(
host
->
mrq
)
{
if
(
host
->
cmd
&&
!
sdhci_data_line_cmd
(
host
->
cmd
)
)
{
pr_err
(
"%s: Timeout waiting for hardware
"
pr_err
(
"%s: Timeout waiting for hardware
cmd interrupt.
\n
"
,
"interrupt.
\n
"
,
mmc_hostname
(
host
->
mmc
));
mmc_hostname
(
host
->
mmc
));
sdhci_dumpregs
(
host
);
sdhci_dumpregs
(
host
);
if
(
host
->
data
)
{
host
->
data
->
error
=
-
ETIMEDOUT
;
sdhci_finish_data
(
host
);
}
else
{
if
(
host
->
cmd
)
host
->
cmd
->
error
=
-
ETIMEDOUT
;
host
->
cmd
->
error
=
-
ETIMEDOUT
;
else
sdhci_finish_mrq
(
host
,
host
->
cmd
->
mrq
);
host
->
mrq
->
cmd
->
error
=
-
ETIMEDOUT
;
tasklet_schedule
(
&
host
->
finish_tasklet
);
}
}
}
mmiowb
();
mmiowb
();
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
}
}
static
void
sdhci_t
uning
_timer
(
unsigned
long
data
)
static
void
sdhci_t
imeout_data
_timer
(
unsigned
long
data
)
{
{
struct
sdhci_host
*
host
;
struct
sdhci_host
*
host
;
unsigned
long
flags
;
unsigned
long
flags
;
...
@@ -2394,8 +2421,25 @@ static void sdhci_tuning_timer(unsigned long data)
...
@@ -2394,8 +2421,25 @@ static void sdhci_tuning_timer(unsigned long data)
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
host
->
flags
|=
SDHCI_NEEDS_RETUNING
;
if
(
host
->
data
||
host
->
data_cmd
||
(
host
->
cmd
&&
sdhci_data_line_cmd
(
host
->
cmd
)))
{
pr_err
(
"%s: Timeout waiting for hardware interrupt.
\n
"
,
mmc_hostname
(
host
->
mmc
));
sdhci_dumpregs
(
host
);
if
(
host
->
data
)
{
host
->
data
->
error
=
-
ETIMEDOUT
;
sdhci_finish_data
(
host
);
}
else
if
(
host
->
data_cmd
)
{
host
->
data_cmd
->
error
=
-
ETIMEDOUT
;
sdhci_finish_mrq
(
host
,
host
->
data_cmd
->
mrq
);
}
else
{
host
->
cmd
->
error
=
-
ETIMEDOUT
;
sdhci_finish_mrq
(
host
,
host
->
cmd
->
mrq
);
}
}
mmiowb
();
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
}
}
...
@@ -2405,56 +2449,48 @@ static void sdhci_tuning_timer(unsigned long data)
...
@@ -2405,56 +2449,48 @@ static void sdhci_tuning_timer(unsigned long data)
* *
* *
\*****************************************************************************/
\*****************************************************************************/
static
void
sdhci_cmd_irq
(
struct
sdhci_host
*
host
,
u32
intmask
,
u32
*
mask
)
static
void
sdhci_cmd_irq
(
struct
sdhci_host
*
host
,
u32
intmask
)
{
{
BUG_ON
(
intmask
==
0
);
if
(
!
host
->
cmd
)
{
if
(
!
host
->
cmd
)
{
pr_err
(
"%s: Got command interrupt 0x%08x even "
/*
"though no command operation was in progress.
\n
"
,
* SDHCI recovers from errors by resetting the cmd and data
* circuits. Until that is done, there very well might be more
* interrupts, so ignore them in that case.
*/
if
(
host
->
pending_reset
)
return
;
pr_err
(
"%s: Got command interrupt 0x%08x even though no command operation was in progress.
\n
"
,
mmc_hostname
(
host
->
mmc
),
(
unsigned
)
intmask
);
mmc_hostname
(
host
->
mmc
),
(
unsigned
)
intmask
);
sdhci_dumpregs
(
host
);
sdhci_dumpregs
(
host
);
return
;
return
;
}
}
if
(
intmask
&
(
SDHCI_INT_TIMEOUT
|
SDHCI_INT_CRC
|
SDHCI_INT_END_BIT
|
SDHCI_INT_INDEX
))
{
if
(
intmask
&
SDHCI_INT_TIMEOUT
)
if
(
intmask
&
SDHCI_INT_TIMEOUT
)
host
->
cmd
->
error
=
-
ETIMEDOUT
;
host
->
cmd
->
error
=
-
ETIMEDOUT
;
else
if
(
intmask
&
(
SDHCI_INT_CRC
|
SDHCI_INT_END_BIT
|
else
SDHCI_INT_INDEX
))
host
->
cmd
->
error
=
-
EILSEQ
;
host
->
cmd
->
error
=
-
EILSEQ
;
if
(
host
->
cmd
->
error
)
{
tasklet_schedule
(
&
host
->
finish_tasklet
);
return
;
}
/*
/*
* The host can send and interrupt when the busy state has
* If this command initiates a data phase and a response
* ended, allowing us to wait without wasting CPU cycles.
* CRC error is signalled, the card can start transferring
* Unfortunately this is overloaded on the "data complete"
* data - the card may have received the command without
* interrupt, so we need to take some care when handling
* error. We must not terminate the mmc_request early.
* it.
*
*
* Note: The 1.0 specification is a bit ambiguous about this
* If the card did not receive the command or returned an
* feature so there might be some problems with older
* error which prevented it sending data, the data phase
* controllers
.
* will time out
.
*/
*/
if
(
host
->
cmd
->
flags
&
MMC_RSP_BUSY
)
{
if
(
host
->
cmd
->
data
&&
if
(
host
->
cmd
->
data
)
(
intmask
&
(
SDHCI_INT_CRC
|
SDHCI_INT_TIMEOUT
))
==
DBG
(
"Cannot wait for busy signal when also "
SDHCI_INT_CRC
)
{
"doing a data transfer"
);
host
->
cmd
=
NULL
;
else
if
(
!
(
host
->
quirks
&
SDHCI_QUIRK_NO_BUSY_IRQ
)
&&
!
host
->
busy_handle
)
{
/* Mark that command complete before busy is ended */
host
->
busy_handle
=
1
;
return
;
return
;
}
}
/* The controller does not support the end-of-busy IRQ,
sdhci_finish_mrq
(
host
,
host
->
cmd
->
mrq
);
* fall through and take the SDHCI_INT_RESPONSE */
return
;
}
else
if
((
host
->
quirks2
&
SDHCI_QUIRK2_STOP_WITH_TC
)
&&
host
->
cmd
->
opcode
==
MMC_STOP_TRANSMISSION
&&
!
host
->
data
)
{
*
mask
&=
~
SDHCI_INT_DATA_END
;
}
}
if
(
intmask
&
SDHCI_INT_RESPONSE
)
if
(
intmask
&
SDHCI_INT_RESPONSE
)
...
@@ -2497,7 +2533,6 @@ static void sdhci_adma_show_error(struct sdhci_host *host) { }
...
@@ -2497,7 +2533,6 @@ static void sdhci_adma_show_error(struct sdhci_host *host) { }
static
void
sdhci_data_irq
(
struct
sdhci_host
*
host
,
u32
intmask
)
static
void
sdhci_data_irq
(
struct
sdhci_host
*
host
,
u32
intmask
)
{
{
u32
command
;
u32
command
;
BUG_ON
(
intmask
==
0
);
/* CMD19 generates _only_ Buffer Read Ready interrupt */
/* CMD19 generates _only_ Buffer Read Ready interrupt */
if
(
intmask
&
SDHCI_INT_DATA_AVAIL
)
{
if
(
intmask
&
SDHCI_INT_DATA_AVAIL
)
{
...
@@ -2511,33 +2546,44 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
...
@@ -2511,33 +2546,44 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
}
}
if
(
!
host
->
data
)
{
if
(
!
host
->
data
)
{
struct
mmc_command
*
data_cmd
=
host
->
data_cmd
;
/*
/*
* The "data complete" interrupt is also used to
* The "data complete" interrupt is also used to
* indicate that a busy state has ended. See comment
* indicate that a busy state has ended. See comment
* above in sdhci_cmd_irq().
* above in sdhci_cmd_irq().
*/
*/
if
(
host
->
cmd
&&
(
host
->
cmd
->
flags
&
MMC_RSP_BUSY
))
{
if
(
data_cmd
&&
(
data_
cmd
->
flags
&
MMC_RSP_BUSY
))
{
if
(
intmask
&
SDHCI_INT_DATA_TIMEOUT
)
{
if
(
intmask
&
SDHCI_INT_DATA_TIMEOUT
)
{
host
->
cmd
->
error
=
-
ETIMEDOUT
;
host
->
data_cmd
=
NULL
;
tasklet_schedule
(
&
host
->
finish_tasklet
);
data_cmd
->
error
=
-
ETIMEDOUT
;
sdhci_finish_mrq
(
host
,
data_cmd
->
mrq
);
return
;
return
;
}
}
if
(
intmask
&
SDHCI_INT_DATA_END
)
{
if
(
intmask
&
SDHCI_INT_DATA_END
)
{
host
->
data_cmd
=
NULL
;
/*
/*
* Some cards handle busy-end interrupt
* Some cards handle busy-end interrupt
* before the command completed, so make
* before the command completed, so make
* sure we do things in the proper order.
* sure we do things in the proper order.
*/
*/
if
(
host
->
busy_handle
)
if
(
host
->
cmd
==
data_cmd
)
sdhci_finish_command
(
host
)
;
return
;
else
host
->
busy_handle
=
1
;
sdhci_finish_mrq
(
host
,
data_cmd
->
mrq
)
;
return
;
return
;
}
}
}
}
pr_err
(
"%s: Got data interrupt 0x%08x even "
/*
"though no data operation was in progress.
\n
"
,
* SDHCI recovers from errors by resetting the cmd and data
* circuits. Until that is done, there very well might be more
* interrupts, so ignore them in that case.
*/
if
(
host
->
pending_reset
)
return
;
pr_err
(
"%s: Got data interrupt 0x%08x even though no data operation was in progress.
\n
"
,
mmc_hostname
(
host
->
mmc
),
(
unsigned
)
intmask
);
mmc_hostname
(
host
->
mmc
),
(
unsigned
)
intmask
);
sdhci_dumpregs
(
host
);
sdhci_dumpregs
(
host
);
...
@@ -2594,7 +2640,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
...
@@ -2594,7 +2640,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
}
}
if
(
intmask
&
SDHCI_INT_DATA_END
)
{
if
(
intmask
&
SDHCI_INT_DATA_END
)
{
if
(
host
->
cmd
)
{
if
(
host
->
cmd
==
host
->
data_cmd
)
{
/*
/*
* Data managed to finish before the
* Data managed to finish before the
* command completed. Make sure we do
* command completed. Make sure we do
...
@@ -2639,17 +2685,10 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
...
@@ -2639,17 +2685,10 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
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
//SDHCI_CARD_PRESENT;
SDHCI_ANY_PRESENT
;
SDHCI_ANY_PRESENT
;
/*
if (!present){
pr_err("sdhci_irq: card not present\n");
present = 1;
}else{
pr_err("sdhci_irq: card is present\n");
}
*/
/*
/*
* There is a observation on i.mx esdhc. INSERT
* There is a observation on i.mx esdhc. INSERT
* bit will be immediately set again when it gets
* bit will be immediately set again when it gets
...
@@ -2677,8 +2716,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
...
@@ -2677,8 +2716,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
}
}
if
(
intmask
&
SDHCI_INT_CMD_MASK
)
if
(
intmask
&
SDHCI_INT_CMD_MASK
)
sdhci_cmd_irq
(
host
,
intmask
&
SDHCI_INT_CMD_MASK
,
sdhci_cmd_irq
(
host
,
intmask
&
SDHCI_INT_CMD_MASK
);
&
intmask
);
if
(
intmask
&
SDHCI_INT_DATA_MASK
)
if
(
intmask
&
SDHCI_INT_DATA_MASK
)
sdhci_data_irq
(
host
,
intmask
&
SDHCI_INT_DATA_MASK
);
sdhci_data_irq
(
host
,
intmask
&
SDHCI_INT_DATA_MASK
);
...
@@ -2687,6 +2725,9 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
...
@@ -2687,6 +2725,9 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
pr_err
(
"%s: Card is consuming too much power!
\n
"
,
pr_err
(
"%s: Card is consuming too much power!
\n
"
,
mmc_hostname
(
host
->
mmc
));
mmc_hostname
(
host
->
mmc
));
if
(
intmask
&
SDHCI_INT_RETUNE
)
mmc_retune_needed
(
host
->
mmc
);
if
(
intmask
&
SDHCI_INT_CARD_INT
)
{
if
(
intmask
&
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
;
...
@@ -2696,7 +2737,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
...
@@ -2696,7 +2737,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
intmask
&=
~
(
SDHCI_INT_CARD_INSERT
|
SDHCI_INT_CARD_REMOVE
|
intmask
&=
~
(
SDHCI_INT_CARD_INSERT
|
SDHCI_INT_CARD_REMOVE
|
SDHCI_INT_CMD_MASK
|
SDHCI_INT_DATA_MASK
|
SDHCI_INT_CMD_MASK
|
SDHCI_INT_DATA_MASK
|
SDHCI_INT_ERROR
|
SDHCI_INT_BUS_POWER
|
SDHCI_INT_ERROR
|
SDHCI_INT_BUS_POWER
|
SDHCI_INT_CARD_INT
);
SDHCI_INT_
RETUNE
|
SDHCI_INT_
CARD_INT
);
if
(
intmask
)
{
if
(
intmask
)
{
unexpected
|=
intmask
;
unexpected
|=
intmask
;
...
@@ -2732,8 +2773,10 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
...
@@ -2732,8 +2773,10 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
if
(
isr
&
(
SDHCI_INT_CARD_INSERT
|
SDHCI_INT_CARD_REMOVE
))
{
if
(
isr
&
(
SDHCI_INT_CARD_INSERT
|
SDHCI_INT_CARD_REMOVE
))
{
sdhci_card_event
(
host
->
mmc
);
struct
mmc_host
*
mmc
=
host
->
mmc
;
mmc_detect_change
(
host
->
mmc
,
msecs_to_jiffies
(
200
));
mmc
->
ops
->
card_event
(
mmc
);
mmc_detect_change
(
mmc
,
msecs_to_jiffies
(
200
));
}
}
if
(
isr
&
SDHCI_INT_CARD_INT
)
{
if
(
isr
&
SDHCI_INT_CARD_INT
)
{
...
@@ -2755,18 +2798,31 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
...
@@ -2755,18 +2798,31 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
\*****************************************************************************/
\*****************************************************************************/
#ifdef CONFIG_PM
#ifdef CONFIG_PM
/*
* To enable wakeup events, the corresponding events have to be enabled in
* the Interrupt Status Enable register too. See 'Table 1-6: Wakeup Signal
* Table' in the SD Host Controller Standard Specification.
* It is useless to restore SDHCI_INT_ENABLE state in
* sdhci_disable_irq_wakeups() since it will be set by
* sdhci_enable_card_detection() or sdhci_init().
*/
void
sdhci_enable_irq_wakeups
(
struct
sdhci_host
*
host
)
void
sdhci_enable_irq_wakeups
(
struct
sdhci_host
*
host
)
{
{
u8
val
;
u8
val
;
u8
mask
=
SDHCI_WAKE_ON_INSERT
|
SDHCI_WAKE_ON_REMOVE
u8
mask
=
SDHCI_WAKE_ON_INSERT
|
SDHCI_WAKE_ON_REMOVE
|
SDHCI_WAKE_ON_INT
;
|
SDHCI_WAKE_ON_INT
;
u32
irq_val
=
SDHCI_INT_CARD_INSERT
|
SDHCI_INT_CARD_REMOVE
|
SDHCI_INT_CARD_INT
;
val
=
sdhci_readb
(
host
,
SDHCI_WAKE_UP_CONTROL
);
val
=
sdhci_readb
(
host
,
SDHCI_WAKE_UP_CONTROL
);
val
|=
mask
;
val
|=
mask
;
/* Avoid fake wake up */
/* Avoid fake wake up */
if
(
host
->
quirks
&
SDHCI_QUIRK_BROKEN_CARD_DETECTION
)
if
(
host
->
quirks
&
SDHCI_QUIRK_BROKEN_CARD_DETECTION
)
{
val
&=
~
(
SDHCI_WAKE_ON_INSERT
|
SDHCI_WAKE_ON_REMOVE
);
val
&=
~
(
SDHCI_WAKE_ON_INSERT
|
SDHCI_WAKE_ON_REMOVE
);
irq_val
&=
~
(
SDHCI_INT_CARD_INSERT
|
SDHCI_INT_CARD_REMOVE
);
}
sdhci_writeb
(
host
,
val
,
SDHCI_WAKE_UP_CONTROL
);
sdhci_writeb
(
host
,
val
,
SDHCI_WAKE_UP_CONTROL
);
sdhci_writel
(
host
,
irq_val
,
SDHCI_INT_ENABLE
);
}
}
EXPORT_SYMBOL_GPL
(
sdhci_enable_irq_wakeups
);
EXPORT_SYMBOL_GPL
(
sdhci_enable_irq_wakeups
);
...
@@ -2785,11 +2841,9 @@ int sdhci_suspend_host(struct sdhci_host *host)
...
@@ -2785,11 +2841,9 @@ int sdhci_suspend_host(struct sdhci_host *host)
{
{
sdhci_disable_card_detection
(
host
);
sdhci_disable_card_detection
(
host
);
/* Disable tuning since we are suspending */
mmc_retune_timer_stop
(
host
->
mmc
);
if
(
host
->
flags
&
SDHCI_USING_RETUNING_TIMER
)
{
if
(
host
->
tuning_mode
!=
SDHCI_TUNING_MODE_3
)
del_timer_sync
(
&
host
->
tuning_timer
);
mmc_retune_needed
(
host
->
mmc
);
host
->
flags
&=
~
SDHCI_NEEDS_RETUNING
;
}
if
(
!
device_may_wakeup
(
mmc_dev
(
host
->
mmc
)))
{
if
(
!
device_may_wakeup
(
mmc_dev
(
host
->
mmc
)))
{
host
->
ier
=
0
;
host
->
ier
=
0
;
...
@@ -2807,6 +2861,7 @@ EXPORT_SYMBOL_GPL(sdhci_suspend_host);
...
@@ -2807,6 +2861,7 @@ EXPORT_SYMBOL_GPL(sdhci_suspend_host);
int
sdhci_resume_host
(
struct
sdhci_host
*
host
)
int
sdhci_resume_host
(
struct
sdhci_host
*
host
)
{
{
struct
mmc_host
*
mmc
=
host
->
mmc
;
int
ret
=
0
;
int
ret
=
0
;
if
(
host
->
flags
&
(
SDHCI_USE_SDMA
|
SDHCI_USE_ADMA
))
{
if
(
host
->
flags
&
(
SDHCI_USE_SDMA
|
SDHCI_USE_ADMA
))
{
...
@@ -2814,76 +2869,43 @@ int sdhci_resume_host(struct sdhci_host *host)
...
@@ -2814,76 +2869,43 @@ int sdhci_resume_host(struct sdhci_host *host)
host
->
ops
->
enable_dma
(
host
);
host
->
ops
->
enable_dma
(
host
);
}
}
if
(
!
device_may_wakeup
(
mmc_dev
(
host
->
mmc
)))
{
ret
=
request_threaded_irq
(
host
->
irq
,
sdhci_irq
,
sdhci_thread_irq
,
IRQF_SHARED
,
mmc_hostname
(
host
->
mmc
),
host
);
if
(
ret
)
return
ret
;
}
else
{
sdhci_disable_irq_wakeups
(
host
);
disable_irq_wake
(
host
->
irq
);
}
if
((
host
->
mmc
->
pm_flags
&
MMC_PM_KEEP_POWER
)
&&
if
((
host
->
mmc
->
pm_flags
&
MMC_PM_KEEP_POWER
)
&&
(
host
->
quirks2
&
SDHCI_QUIRK2_HOST_OFF_CARD_ON
))
{
(
host
->
quirks2
&
SDHCI_QUIRK2_HOST_OFF_CARD_ON
))
{
/* Card keeps power but host controller does not */
/* Card keeps power but host controller does not */
sdhci_init
(
host
,
0
);
sdhci_init
(
host
,
0
);
host
->
pwr
=
0
;
host
->
pwr
=
0
;
host
->
clock
=
0
;
host
->
clock
=
0
;
sdhci_do_set_ios
(
host
,
&
host
->
mmc
->
ios
);
mmc
->
ops
->
set_ios
(
mmc
,
&
mmc
->
ios
);
}
else
{
}
else
{
sdhci_init
(
host
,
(
host
->
mmc
->
pm_flags
&
MMC_PM_KEEP_POWER
));
sdhci_init
(
host
,
(
host
->
mmc
->
pm_flags
&
MMC_PM_KEEP_POWER
));
mmiowb
();
mmiowb
();
}
}
sdhci_enable_card_detection
(
host
);
if
(
!
device_may_wakeup
(
mmc_dev
(
host
->
mmc
)))
{
ret
=
request_threaded_irq
(
host
->
irq
,
sdhci_irq
,
sdhci_thread_irq
,
IRQF_SHARED
,
mmc_hostname
(
host
->
mmc
),
host
);
if
(
ret
)
return
ret
;
}
else
{
sdhci_disable_irq_wakeups
(
host
);
disable_irq_wake
(
host
->
irq
);
}
/* Set the re-tuning expiration flag */
sdhci_enable_card_detection
(
host
);
if
(
host
->
flags
&
SDHCI_USING_RETUNING_TIMER
)
host
->
flags
|=
SDHCI_NEEDS_RETUNING
;
return
ret
;
return
ret
;
}
}
EXPORT_SYMBOL_GPL
(
sdhci_resume_host
);
EXPORT_SYMBOL_GPL
(
sdhci_resume_host
);
static
int
sdhci_runtime_pm_get
(
struct
sdhci_host
*
host
)
{
return
pm_runtime_get_sync
(
host
->
mmc
->
parent
);
}
static
int
sdhci_runtime_pm_put
(
struct
sdhci_host
*
host
)
{
pm_runtime_mark_last_busy
(
host
->
mmc
->
parent
);
return
pm_runtime_put_autosuspend
(
host
->
mmc
->
parent
);
}
static
void
sdhci_runtime_pm_bus_on
(
struct
sdhci_host
*
host
)
{
if
(
host
->
runtime_suspended
||
host
->
bus_on
)
return
;
host
->
bus_on
=
true
;
pm_runtime_get_noresume
(
host
->
mmc
->
parent
);
}
static
void
sdhci_runtime_pm_bus_off
(
struct
sdhci_host
*
host
)
{
if
(
host
->
runtime_suspended
||
!
host
->
bus_on
)
return
;
host
->
bus_on
=
false
;
pm_runtime_put_noidle
(
host
->
mmc
->
parent
);
}
int
sdhci_runtime_suspend_host
(
struct
sdhci_host
*
host
)
int
sdhci_runtime_suspend_host
(
struct
sdhci_host
*
host
)
{
{
unsigned
long
flags
;
unsigned
long
flags
;
/* Disable tuning since we are suspending */
mmc_retune_timer_stop
(
host
->
mmc
);
if
(
host
->
flags
&
SDHCI_USING_RETUNING_TIMER
)
{
if
(
host
->
tuning_mode
!=
SDHCI_TUNING_MODE_3
)
del_timer_sync
(
&
host
->
tuning_timer
);
mmc_retune_needed
(
host
->
mmc
);
host
->
flags
&=
~
SDHCI_NEEDS_RETUNING
;
}
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
host
->
ier
&=
SDHCI_INT_CARD_INT
;
host
->
ier
&=
SDHCI_INT_CARD_INT
;
...
@@ -2903,6 +2925,7 @@ EXPORT_SYMBOL_GPL(sdhci_runtime_suspend_host);
...
@@ -2903,6 +2925,7 @@ EXPORT_SYMBOL_GPL(sdhci_runtime_suspend_host);
int
sdhci_runtime_resume_host
(
struct
sdhci_host
*
host
)
int
sdhci_runtime_resume_host
(
struct
sdhci_host
*
host
)
{
{
struct
mmc_host
*
mmc
=
host
->
mmc
;
unsigned
long
flags
;
unsigned
long
flags
;
int
host_flags
=
host
->
flags
;
int
host_flags
=
host
->
flags
;
...
@@ -2916,8 +2939,8 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
...
@@ -2916,8 +2939,8 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
/* Force clock and power re-program */
/* Force clock and power re-program */
host
->
pwr
=
0
;
host
->
pwr
=
0
;
host
->
clock
=
0
;
host
->
clock
=
0
;
sdhci_do_start_signal_voltage_switch
(
host
,
&
host
->
mmc
->
ios
);
mmc
->
ops
->
start_signal_voltage_switch
(
mmc
,
&
mmc
->
ios
);
sdhci_do_set_ios
(
host
,
&
host
->
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
))
{
...
@@ -2926,9 +2949,9 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
...
@@ -2926,9 +2949,9 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
}
}
/* Set the re-tuning expiration flag */
if
((
mmc
->
caps2
&
MMC_CAP2_HS400_ES
)
&&
if
(
host
->
flags
&
SDHCI_USING_RETUNING_TIMER
)
mmc
->
ops
->
hs400_enhanced_strobe
)
host
->
flags
|=
SDHCI_NEEDS_RETUNING
;
mmc
->
ops
->
hs400_enhanced_strobe
(
mmc
,
&
mmc
->
ios
)
;
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
...
@@ -2969,19 +2992,85 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
...
@@ -2969,19 +2992,85 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
host
=
mmc_priv
(
mmc
);
host
=
mmc_priv
(
mmc
);
host
->
mmc
=
mmc
;
host
->
mmc
=
mmc
;
host
->
mmc_host_ops
=
sdhci_ops
;
mmc
->
ops
=
&
host
->
mmc_host_ops
;
host
->
flags
=
SDHCI_SIGNALING_330
;
return
host
;
return
host
;
}
}
EXPORT_SYMBOL_GPL
(
sdhci_alloc_host
);
EXPORT_SYMBOL_GPL
(
sdhci_alloc_host
);
int
sdhci_add_host
(
struct
sdhci_host
*
host
)
static
int
sdhci_set_dma_mask
(
struct
sdhci_host
*
host
)
{
struct
mmc_host
*
mmc
=
host
->
mmc
;
struct
device
*
dev
=
mmc_dev
(
mmc
);
int
ret
=
-
EINVAL
;
if
(
host
->
quirks2
&
SDHCI_QUIRK2_BROKEN_64_BIT_DMA
)
host
->
flags
&=
~
SDHCI_USE_64_BIT_DMA
;
/* Try 64-bit mask if hardware is capable of it */
if
(
host
->
flags
&
SDHCI_USE_64_BIT_DMA
)
{
ret
=
dma_set_mask_and_coherent
(
dev
,
DMA_BIT_MASK
(
64
));
if
(
ret
)
{
pr_warn
(
"%s: Failed to set 64-bit DMA mask.
\n
"
,
mmc_hostname
(
mmc
));
host
->
flags
&=
~
SDHCI_USE_64_BIT_DMA
;
}
}
/* 32-bit mask as default & fallback */
if
(
ret
)
{
ret
=
dma_set_mask_and_coherent
(
dev
,
DMA_BIT_MASK
(
32
));
if
(
ret
)
pr_warn
(
"%s: Failed to set 32-bit DMA mask.
\n
"
,
mmc_hostname
(
mmc
));
}
return
ret
;
}
void
__sdhci_read_caps
(
struct
sdhci_host
*
host
,
u16
*
ver
,
u32
*
caps
,
u32
*
caps1
)
{
u16
v
;
if
(
host
->
read_caps
)
return
;
host
->
read_caps
=
true
;
if
(
debug_quirks
)
host
->
quirks
=
debug_quirks
;
if
(
debug_quirks2
)
host
->
quirks2
=
debug_quirks2
;
sdhci_do_reset
(
host
,
SDHCI_RESET_ALL
);
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
(
host
->
version
<
SDHCI_SPEC_300
)
return
;
host
->
caps1
=
caps1
?
*
caps1
:
sdhci_readl
(
host
,
SDHCI_CAPABILITIES_1
);
}
EXPORT_SYMBOL_GPL
(
__sdhci_read_caps
);
int
sdhci_setup_host
(
struct
sdhci_host
*
host
)
{
{
struct
mmc_host
*
mmc
;
struct
mmc_host
*
mmc
;
u32
caps
[
2
]
=
{
0
,
0
};
u32
max_current_caps
;
u32
max_current_caps
;
unsigned
int
ocr_avail
;
unsigned
int
ocr_avail
;
unsigned
int
override_timeout_clk
;
unsigned
int
override_timeout_clk
;
u32
max_clk
;
int
ret
;
int
ret
;
WARN_ON
(
host
==
NULL
);
WARN_ON
(
host
==
NULL
);
...
@@ -2990,35 +3079,28 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -2990,35 +3079,28 @@ int sdhci_add_host(struct sdhci_host *host)
mmc
=
host
->
mmc
;
mmc
=
host
->
mmc
;
if
(
debug_quirks
)
/*
host
->
quirks
=
debug_quirks
;
* If there are external regulators, get them. Note this must be done
if
(
debug_quirks2
)
* early before resetting the host and reading the capabilities so that
host
->
quirks2
=
debug_quirks2
;
* the host can take the appropriate action if regulators are not
* available.
*/
ret
=
mmc_regulator_get_supply
(
mmc
);
if
(
ret
==
-
EPROBE_DEFER
)
return
ret
;
override_timeout_clk
=
host
->
timeout_clk
;
sdhci_read_caps
(
host
)
;
sdhci_do_reset
(
host
,
SDHCI_RESET_ALL
)
;
override_timeout_clk
=
host
->
timeout_clk
;
host
->
version
=
sdhci_readw
(
host
,
SDHCI_HOST_VERSION
);
host
->
version
=
(
host
->
version
&
SDHCI_SPEC_VER_MASK
)
>>
SDHCI_SPEC_VER_SHIFT
;
if
(
host
->
version
>
SDHCI_SPEC_300
)
{
if
(
host
->
version
>
SDHCI_SPEC_300
)
{
pr_err
(
"%s: Unknown controller version (%d). "
pr_err
(
"%s: Unknown controller version (%d). You may experience problems.
\n
"
,
"You may experience problems.
\n
"
,
mmc_hostname
(
mmc
),
mmc_hostname
(
mmc
),
host
->
version
);
host
->
version
);
}
}
caps
[
0
]
=
(
host
->
quirks
&
SDHCI_QUIRK_MISSING_CAPS
)
?
host
->
caps
:
sdhci_readl
(
host
,
SDHCI_CAPABILITIES
);
if
(
host
->
version
>=
SDHCI_SPEC_300
)
caps
[
1
]
=
(
host
->
quirks
&
SDHCI_QUIRK_MISSING_CAPS
)
?
host
->
caps1
:
sdhci_readl
(
host
,
SDHCI_CAPABILITIES_1
);
if
(
host
->
quirks
&
SDHCI_QUIRK_FORCE_DMA
)
if
(
host
->
quirks
&
SDHCI_QUIRK_FORCE_DMA
)
host
->
flags
|=
SDHCI_USE_SDMA
;
host
->
flags
|=
SDHCI_USE_SDMA
;
else
if
(
!
(
caps
[
0
]
&
SDHCI_CAN_DO_SDMA
))
else
if
(
!
(
host
->
caps
&
SDHCI_CAN_DO_SDMA
))
DBG
(
"Controller doesn't have SDMA capability
\n
"
);
DBG
(
"Controller doesn't have SDMA capability
\n
"
);
else
else
host
->
flags
|=
SDHCI_USE_SDMA
;
host
->
flags
|=
SDHCI_USE_SDMA
;
...
@@ -3030,7 +3112,7 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3030,7 +3112,7 @@ int sdhci_add_host(struct sdhci_host *host)
}
}
if
((
host
->
version
>=
SDHCI_SPEC_200
)
&&
if
((
host
->
version
>=
SDHCI_SPEC_200
)
&&
(
caps
[
0
]
&
SDHCI_CAN_DO_ADMA2
))
(
host
->
caps
&
SDHCI_CAN_DO_ADMA2
))
host
->
flags
|=
SDHCI_USE_ADMA
;
host
->
flags
|=
SDHCI_USE_ADMA
;
if
((
host
->
quirks
&
SDHCI_QUIRK_BROKEN_ADMA
)
&&
if
((
host
->
quirks
&
SDHCI_QUIRK_BROKEN_ADMA
)
&&
...
@@ -3046,17 +3128,21 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3046,17 +3128,21 @@ int sdhci_add_host(struct sdhci_host *host)
* SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to
* SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to
* implement.
* implement.
*/
*/
if
(
sdhci_readl
(
host
,
SDHCI_CAPABILITIES
)
&
SDHCI_CAN_64BIT
)
if
(
host
->
caps
&
SDHCI_CAN_64BIT
)
host
->
flags
|=
SDHCI_USE_64_BIT_DMA
;
host
->
flags
|=
SDHCI_USE_64_BIT_DMA
;
if
(
host
->
flags
&
(
SDHCI_USE_SDMA
|
SDHCI_USE_ADMA
))
{
if
(
host
->
flags
&
(
SDHCI_USE_SDMA
|
SDHCI_USE_ADMA
))
{
if
(
host
->
ops
->
enable_dma
)
{
ret
=
sdhci_set_dma_mask
(
host
);
if
(
host
->
ops
->
enable_dma
(
host
))
{
if
(
!
ret
&&
host
->
ops
->
enable_dma
)
ret
=
host
->
ops
->
enable_dma
(
host
);
if
(
ret
)
{
pr_warn
(
"%s: No suitable DMA available - falling back to PIO
\n
"
,
pr_warn
(
"%s: No suitable DMA available - falling back to PIO
\n
"
,
mmc_hostname
(
mmc
));
mmc_hostname
(
mmc
));
host
->
flags
&=
host
->
flags
&=
~
(
SDHCI_USE_SDMA
|
SDHCI_USE_ADMA
);
~
(
SDHCI_USE_SDMA
|
SDHCI_USE_ADMA
);
}
ret
=
0
;
}
}
}
}
...
@@ -3065,6 +3151,9 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3065,6 +3151,9 @@ int sdhci_add_host(struct sdhci_host *host)
host
->
flags
&=
~
SDHCI_USE_SDMA
;
host
->
flags
&=
~
SDHCI_USE_SDMA
;
if
(
host
->
flags
&
SDHCI_USE_ADMA
)
{
if
(
host
->
flags
&
SDHCI_USE_ADMA
)
{
dma_addr_t
dma
;
void
*
buf
;
/*
/*
* The DMA descriptor table size is calculated as the maximum
* The DMA descriptor table size is calculated as the maximum
* number of segments times 2, to allow for an alignment
* number of segments times 2, to allow for an alignment
...
@@ -3074,43 +3163,33 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3074,43 +3163,33 @@ int sdhci_add_host(struct sdhci_host *host)
if
(
host
->
flags
&
SDHCI_USE_64_BIT_DMA
)
{
if
(
host
->
flags
&
SDHCI_USE_64_BIT_DMA
)
{
host
->
adma_table_sz
=
(
SDHCI_MAX_SEGS
*
2
+
1
)
*
host
->
adma_table_sz
=
(
SDHCI_MAX_SEGS
*
2
+
1
)
*
SDHCI_ADMA2_64_DESC_SZ
;
SDHCI_ADMA2_64_DESC_SZ
;
host
->
align_buffer_sz
=
SDHCI_MAX_SEGS
*
SDHCI_ADMA2_64_ALIGN
;
host
->
desc_sz
=
SDHCI_ADMA2_64_DESC_SZ
;
host
->
desc_sz
=
SDHCI_ADMA2_64_DESC_SZ
;
host
->
align_sz
=
SDHCI_ADMA2_64_ALIGN
;
host
->
align_mask
=
SDHCI_ADMA2_64_ALIGN
-
1
;
}
else
{
}
else
{
host
->
adma_table_sz
=
(
SDHCI_MAX_SEGS
*
2
+
1
)
*
host
->
adma_table_sz
=
(
SDHCI_MAX_SEGS
*
2
+
1
)
*
SDHCI_ADMA2_32_DESC_SZ
;
SDHCI_ADMA2_32_DESC_SZ
;
host
->
align_buffer_sz
=
SDHCI_MAX_SEGS
*
SDHCI_ADMA2_32_ALIGN
;
host
->
desc_sz
=
SDHCI_ADMA2_32_DESC_SZ
;
host
->
desc_sz
=
SDHCI_ADMA2_32_DESC_SZ
;
host
->
align_sz
=
SDHCI_ADMA2_32_ALIGN
;
}
host
->
align_mask
=
SDHCI_ADMA2_32_ALIGN
-
1
;
}
host
->
align_buffer_sz
=
SDHCI_MAX_SEGS
*
SDHCI_ADMA2_ALIGN
;
host
->
adma_table
=
dma_alloc_coherent
(
mmc_dev
(
mmc
),
buf
=
dma_alloc_coherent
(
mmc_dev
(
mmc
),
host
->
align_buffer_sz
+
host
->
adma_table_sz
,
host
->
adma_table_sz
,
&
dma
,
GFP_KERNEL
);
&
host
->
adma_addr
,
if
(
!
buf
)
{
GFP_KERNEL
);
host
->
align_buffer
=
kmalloc
(
host
->
align_buffer_sz
,
GFP_KERNEL
);
if
(
!
host
->
adma_table
||
!
host
->
align_buffer
)
{
dma_free_coherent
(
mmc_dev
(
mmc
),
host
->
adma_table_sz
,
host
->
adma_table
,
host
->
adma_addr
);
kfree
(
host
->
align_buffer
);
pr_warn
(
"%s: Unable to allocate ADMA buffers - falling back to standard DMA
\n
"
,
pr_warn
(
"%s: Unable to allocate ADMA buffers - falling back to standard DMA
\n
"
,
mmc_hostname
(
mmc
));
mmc_hostname
(
mmc
));
host
->
flags
&=
~
SDHCI_USE_ADMA
;
host
->
flags
&=
~
SDHCI_USE_ADMA
;
host
->
adma_table
=
NULL
;
}
else
if
((
dma
+
host
->
align_buffer_sz
)
&
host
->
align_buffer
=
NULL
;
(
SDHCI_ADMA2_DESC_ALIGN
-
1
))
{
}
else
if
(
host
->
adma_addr
&
host
->
align_mask
)
{
pr_warn
(
"%s: unable to allocate aligned ADMA descriptor
\n
"
,
pr_warn
(
"%s: unable to allocate aligned ADMA descriptor
\n
"
,
mmc_hostname
(
mmc
));
mmc_hostname
(
mmc
));
host
->
flags
&=
~
SDHCI_USE_ADMA
;
host
->
flags
&=
~
SDHCI_USE_ADMA
;
dma_free_coherent
(
mmc_dev
(
mmc
),
host
->
adma_table_sz
,
dma_free_coherent
(
mmc_dev
(
mmc
),
host
->
align_buffer_sz
+
host
->
adma_table
,
host
->
adma_addr
);
host
->
adma_table_sz
,
buf
,
dma
);
kfree
(
host
->
align_buffer
);
}
else
{
host
->
adma_table
=
NULL
;
host
->
align_buffer
=
buf
;
host
->
align_buffer
=
NULL
;
host
->
align_addr
=
dma
;
host
->
adma_table
=
buf
+
host
->
align_buffer_sz
;
host
->
adma_addr
=
dma
+
host
->
align_buffer_sz
;
}
}
}
}
...
@@ -3125,29 +3204,29 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3125,29 +3204,29 @@ int sdhci_add_host(struct sdhci_host *host)
}
}
if
(
host
->
version
>=
SDHCI_SPEC_300
)
if
(
host
->
version
>=
SDHCI_SPEC_300
)
host
->
max_clk
=
(
caps
[
0
]
&
SDHCI_CLOCK_V3_BASE_MASK
)
host
->
max_clk
=
(
host
->
caps
&
SDHCI_CLOCK_V3_BASE_MASK
)
>>
SDHCI_CLOCK_BASE_SHIFT
;
>>
SDHCI_CLOCK_BASE_SHIFT
;
else
else
host
->
max_clk
=
(
caps
[
0
]
&
SDHCI_CLOCK_BASE_MASK
)
host
->
max_clk
=
(
host
->
caps
&
SDHCI_CLOCK_BASE_MASK
)
>>
SDHCI_CLOCK_BASE_SHIFT
;
>>
SDHCI_CLOCK_BASE_SHIFT
;
host
->
max_clk
*=
1000000
;
host
->
max_clk
*=
1000000
;
if
(
host
->
max_clk
==
0
||
host
->
quirks
&
if
(
host
->
max_clk
==
0
||
host
->
quirks
&
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN
)
{
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN
)
{
if
(
!
host
->
ops
->
get_max_clock
)
{
if
(
!
host
->
ops
->
get_max_clock
)
{
pr_err
(
"%s: Hardware doesn't specify base clock "
pr_err
(
"%s: Hardware doesn't specify base clock frequency.
\n
"
,
"frequency.
\n
"
,
mmc_hostname
(
mmc
));
mmc_hostname
(
mmc
));
return
-
ENODEV
;
ret
=
-
ENODEV
;
goto
undma
;
}
}
host
->
max_clk
=
host
->
ops
->
get_max_clock
(
host
);
host
->
max_clk
=
host
->
ops
->
get_max_clock
(
host
);
}
}
host
->
next_data
.
cookie
=
1
;
/*
/*
* In case of Host Controller v3.00, find out whether clock
* In case of Host Controller v3.00, find out whether clock
* multiplier is supported.
* multiplier is supported.
*/
*/
host
->
clk_mul
=
(
caps
[
1
]
&
SDHCI_CLOCK_MUL_MASK
)
>>
host
->
clk_mul
=
(
host
->
caps1
&
SDHCI_CLOCK_MUL_MASK
)
>>
SDHCI_CLOCK_MUL_SHIFT
;
SDHCI_CLOCK_MUL_SHIFT
;
/*
/*
...
@@ -3162,21 +3241,24 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3162,21 +3241,24 @@ int sdhci_add_host(struct sdhci_host *host)
/*
/*
* Set host parameters.
* Set host parameters.
*/
*/
m
mc
->
ops
=
&
sdhci_ops
;
m
ax_clk
=
host
->
max_clk
;
mmc
->
f_max
=
host
->
max_clk
;
if
(
host
->
ops
->
get_min_clock
)
if
(
host
->
ops
->
get_min_clock
)
mmc
->
f_min
=
host
->
ops
->
get_min_clock
(
host
);
mmc
->
f_min
=
host
->
ops
->
get_min_clock
(
host
);
else
if
(
host
->
version
>=
SDHCI_SPEC_300
)
{
else
if
(
host
->
version
>=
SDHCI_SPEC_300
)
{
if
(
host
->
clk_mul
)
{
if
(
host
->
clk_mul
)
{
mmc
->
f_min
=
(
host
->
max_clk
*
host
->
clk_mul
)
/
1024
;
mmc
->
f_min
=
(
host
->
max_clk
*
host
->
clk_mul
)
/
1024
;
m
mc
->
f_max
=
host
->
max_clk
*
host
->
clk_mul
;
m
ax_clk
=
host
->
max_clk
*
host
->
clk_mul
;
}
else
}
else
mmc
->
f_min
=
host
->
max_clk
/
SDHCI_MAX_DIV_SPEC_300
;
mmc
->
f_min
=
host
->
max_clk
/
SDHCI_MAX_DIV_SPEC_300
;
}
else
}
else
mmc
->
f_min
=
host
->
max_clk
/
SDHCI_MAX_DIV_SPEC_200
;
mmc
->
f_min
=
host
->
max_clk
/
SDHCI_MAX_DIV_SPEC_200
;
if
(
!
mmc
->
f_max
||
mmc
->
f_max
>
max_clk
)
mmc
->
f_max
=
max_clk
;
if
(
!
(
host
->
quirks
&
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
))
{
if
(
!
(
host
->
quirks
&
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
))
{
host
->
timeout_clk
=
(
caps
[
0
]
&
SDHCI_TIMEOUT_CLK_MASK
)
>>
host
->
timeout_clk
=
(
host
->
caps
&
SDHCI_TIMEOUT_CLK_MASK
)
>>
SDHCI_TIMEOUT_CLK_SHIFT
;
SDHCI_TIMEOUT_CLK_SHIFT
;
if
(
host
->
timeout_clk
==
0
)
{
if
(
host
->
timeout_clk
==
0
)
{
if
(
host
->
ops
->
get_timeout_clock
)
{
if
(
host
->
ops
->
get_timeout_clock
)
{
...
@@ -3185,21 +3267,22 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3185,21 +3267,22 @@ int sdhci_add_host(struct sdhci_host *host)
}
else
{
}
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
));
return
-
ENODEV
;
ret
=
-
ENODEV
;
goto
undma
;
}
}
}
}
if
(
caps
[
0
]
&
SDHCI_TIMEOUT_CLK_UNIT
)
if
(
host
->
caps
&
SDHCI_TIMEOUT_CLK_UNIT
)
host
->
timeout_clk
*=
1000
;
host
->
timeout_clk
*=
1000
;
if
(
override_timeout_clk
)
host
->
timeout_clk
=
override_timeout_clk
;
mmc
->
max_busy_timeout
=
host
->
ops
->
get_max_timeout_count
?
mmc
->
max_busy_timeout
=
host
->
ops
->
get_max_timeout_count
?
host
->
ops
->
get_max_timeout_count
(
host
)
:
1
<<
27
;
host
->
ops
->
get_max_timeout_count
(
host
)
:
1
<<
27
;
mmc
->
max_busy_timeout
/=
host
->
timeout_clk
;
mmc
->
max_busy_timeout
/=
host
->
timeout_clk
;
}
}
if
(
override_timeout_clk
)
host
->
timeout_clk
=
override_timeout_clk
;
mmc
->
caps
|=
MMC_CAP_SDIO_IRQ
|
MMC_CAP_ERASE
|
MMC_CAP_CMD23
;
mmc
->
caps
|=
MMC_CAP_SDIO_IRQ
|
MMC_CAP_ERASE
|
MMC_CAP_CMD23
;
mmc
->
caps2
|=
MMC_CAP2_SDIO_IRQ_NOTHREAD
;
mmc
->
caps2
|=
MMC_CAP2_SDIO_IRQ_NOTHREAD
;
...
@@ -3209,7 +3292,8 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3209,7 +3292,8 @@ int sdhci_add_host(struct sdhci_host *host)
/* Auto-CMD23 stuff only works in ADMA or PIO. */
/* Auto-CMD23 stuff only works in ADMA or PIO. */
if
((
host
->
version
>=
SDHCI_SPEC_300
)
&&
if
((
host
->
version
>=
SDHCI_SPEC_300
)
&&
((
host
->
flags
&
SDHCI_USE_ADMA
)
||
((
host
->
flags
&
SDHCI_USE_ADMA
)
||
!
(
host
->
flags
&
SDHCI_USE_SDMA
)))
{
!
(
host
->
flags
&
SDHCI_USE_SDMA
))
&&
!
(
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
(
"%s: Auto-CMD23 available
\n
"
,
mmc_hostname
(
mmc
));
}
else
{
}
else
{
...
@@ -3229,23 +3313,21 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3229,23 +3313,21 @@ int sdhci_add_host(struct sdhci_host *host)
if
(
host
->
quirks2
&
SDHCI_QUIRK2_HOST_NO_CMD23
)
if
(
host
->
quirks2
&
SDHCI_QUIRK2_HOST_NO_CMD23
)
mmc
->
caps
&=
~
MMC_CAP_CMD23
;
mmc
->
caps
&=
~
MMC_CAP_CMD23
;
if
(
caps
[
0
]
&
SDHCI_CAN_DO_HISPD
)
if
((
host
->
caps
&
SDHCI_CAN_DO_HISPD
)
&&
!
(
host
->
quirks
&
SDHCI_QUIRK_NO_HISPD_BIT
))
mmc
->
caps
|=
MMC_CAP_SD_HIGHSPEED
|
MMC_CAP_MMC_HIGHSPEED
;
mmc
->
caps
|=
MMC_CAP_SD_HIGHSPEED
|
MMC_CAP_MMC_HIGHSPEED
;
if
((
host
->
quirks
&
SDHCI_QUIRK_BROKEN_CARD_DETECTION
)
&&
if
((
host
->
quirks
&
SDHCI_QUIRK_BROKEN_CARD_DETECTION
)
&&
!
(
mmc
->
caps
&
MMC_CAP_NONREMOVABLE
))
mmc_card_is_removable
(
mmc
)
&&
mmc_gpio_get_cd
(
host
->
mmc
)
<
0
)
mmc
->
caps
|=
MMC_CAP_NEEDS_POLL
;
mmc
->
caps
|=
MMC_CAP_NEEDS_POLL
;
/* If there are external regulators, get them */
if
(
mmc_regulator_get_supply
(
mmc
)
==
-
EPROBE_DEFER
)
return
-
EPROBE_DEFER
;
/* If vqmmc regulator and no 1.8V signalling, then there's no UHS */
/* If vqmmc regulator and no 1.8V signalling, then there's no UHS */
if
(
!
IS_ERR
(
mmc
->
supply
.
vqmmc
))
{
if
(
!
IS_ERR
(
mmc
->
supply
.
vqmmc
))
{
ret
=
regulator_enable
(
mmc
->
supply
.
vqmmc
);
ret
=
regulator_enable
(
mmc
->
supply
.
vqmmc
);
if
(
!
regulator_is_supported_voltage
(
mmc
->
supply
.
vqmmc
,
1700000
,
if
(
!
regulator_is_supported_voltage
(
mmc
->
supply
.
vqmmc
,
1700000
,
1950000
))
1950000
))
caps
[
1
]
&=
~
(
SDHCI_SUPPORT_SDR104
|
host
->
caps1
&=
~
(
SDHCI_SUPPORT_SDR104
|
SDHCI_SUPPORT_SDR50
|
SDHCI_SUPPORT_SDR50
|
SDHCI_SUPPORT_DDR50
);
SDHCI_SUPPORT_DDR50
);
if
(
ret
)
{
if
(
ret
)
{
...
@@ -3255,28 +3337,30 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3255,28 +3337,30 @@ int sdhci_add_host(struct sdhci_host *host)
}
}
}
}
if
(
host
->
quirks2
&
SDHCI_QUIRK2_NO_1_8_V
)
if
(
host
->
quirks2
&
SDHCI_QUIRK2_NO_1_8_V
)
{
caps
[
1
]
&=
~
(
SDHCI_SUPPORT_SDR104
|
SDHCI_SUPPORT_SDR50
|
host
->
caps1
&=
~
(
SDHCI_SUPPORT_SDR104
|
SDHCI_SUPPORT_SDR50
|
SDHCI_SUPPORT_DDR50
);
SDHCI_SUPPORT_DDR50
);
}
/* Any UHS-I mode in caps implies SDR12 and SDR25 support. */
/* Any UHS-I mode in caps implies SDR12 and SDR25 support. */
if
(
caps
[
1
]
&
(
SDHCI_SUPPORT_SDR104
|
SDHCI_SUPPORT_SDR50
|
if
(
host
->
caps1
&
(
SDHCI_SUPPORT_SDR104
|
SDHCI_SUPPORT_SDR50
|
SDHCI_SUPPORT_DDR50
))
SDHCI_SUPPORT_DDR50
))
mmc
->
caps
|=
MMC_CAP_UHS_SDR12
|
MMC_CAP_UHS_SDR25
;
mmc
->
caps
|=
MMC_CAP_UHS_SDR12
|
MMC_CAP_UHS_SDR25
;
/* SDR104 supports also implies SDR50 support */
/* SDR104 supports also implies SDR50 support */
if
(
caps
[
1
]
&
SDHCI_SUPPORT_SDR104
)
{
if
(
host
->
caps1
&
SDHCI_SUPPORT_SDR104
)
{
mmc
->
caps
|=
MMC_CAP_UHS_SDR104
|
MMC_CAP_UHS_SDR50
;
mmc
->
caps
|=
MMC_CAP_UHS_SDR104
|
MMC_CAP_UHS_SDR50
;
/* SD3.0: SDR104 is supported so (for eMMC) the caps2
/* SD3.0: SDR104 is supported so (for eMMC) the caps2
* field can be promoted to support HS200.
* field can be promoted to support HS200.
*/
*/
if
(
!
(
host
->
quirks2
&
SDHCI_QUIRK2_BROKEN_HS200
))
if
(
!
(
host
->
quirks2
&
SDHCI_QUIRK2_BROKEN_HS200
))
mmc
->
caps2
|=
MMC_CAP2_HS200
;
mmc
->
caps2
|=
MMC_CAP2_HS200
;
}
else
if
(
caps
[
1
]
&
SDHCI_SUPPORT_SDR50
)
}
else
if
(
host
->
caps1
&
SDHCI_SUPPORT_SDR50
)
{
mmc
->
caps
|=
MMC_CAP_UHS_SDR50
;
mmc
->
caps
|=
MMC_CAP_UHS_SDR50
;
}
if
(
host
->
quirks2
&
SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400
&&
if
(
host
->
quirks2
&
SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400
&&
(
caps
[
1
]
&
SDHCI_SUPPORT_HS400
))
(
host
->
caps1
&
SDHCI_SUPPORT_HS400
))
mmc
->
caps2
|=
MMC_CAP2_HS400
;
mmc
->
caps2
|=
MMC_CAP2_HS400
;
if
((
mmc
->
caps2
&
MMC_CAP2_HSX00_1_2V
)
&&
if
((
mmc
->
caps2
&
MMC_CAP2_HSX00_1_2V
)
&&
...
@@ -3285,28 +3369,24 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3285,28 +3369,24 @@ int sdhci_add_host(struct sdhci_host *host)
1300000
)))
1300000
)))
mmc
->
caps2
&=
~
MMC_CAP2_HSX00_1_2V
;
mmc
->
caps2
&=
~
MMC_CAP2_HSX00_1_2V
;
if
((
caps
[
1
]
&
SDHCI_SUPPORT_DDR50
)
&&
if
((
host
->
caps1
&
SDHCI_SUPPORT_DDR50
)
&&
!
(
host
->
quirks2
&
SDHCI_QUIRK2_BROKEN_DDR50
))
!
(
host
->
quirks2
&
SDHCI_QUIRK2_BROKEN_DDR50
))
mmc
->
caps
|=
MMC_CAP_UHS_DDR50
;
mmc
->
caps
|=
MMC_CAP_UHS_DDR50
;
/* Does the host need tuning for SDR50? */
/* Does the host need tuning for SDR50? */
if
(
caps
[
1
]
&
SDHCI_USE_SDR50_TUNING
)
if
(
host
->
caps1
&
SDHCI_USE_SDR50_TUNING
)
host
->
flags
|=
SDHCI_SDR50_NEEDS_TUNING
;
host
->
flags
|=
SDHCI_SDR50_NEEDS_TUNING
;
/* Does the host need tuning for SDR104 / HS200? */
if
(
mmc
->
caps2
&
MMC_CAP2_HS200
)
host
->
flags
|=
SDHCI_SDR104_NEEDS_TUNING
;
/* Driver Type(s) (A, C, D) supported by the host */
/* Driver Type(s) (A, C, D) supported by the host */
if
(
caps
[
1
]
&
SDHCI_DRIVER_TYPE_A
)
if
(
host
->
caps1
&
SDHCI_DRIVER_TYPE_A
)
mmc
->
caps
|=
MMC_CAP_DRIVER_TYPE_A
;
mmc
->
caps
|=
MMC_CAP_DRIVER_TYPE_A
;
if
(
caps
[
1
]
&
SDHCI_DRIVER_TYPE_C
)
if
(
host
->
caps1
&
SDHCI_DRIVER_TYPE_C
)
mmc
->
caps
|=
MMC_CAP_DRIVER_TYPE_C
;
mmc
->
caps
|=
MMC_CAP_DRIVER_TYPE_C
;
if
(
caps
[
1
]
&
SDHCI_DRIVER_TYPE_D
)
if
(
host
->
caps1
&
SDHCI_DRIVER_TYPE_D
)
mmc
->
caps
|=
MMC_CAP_DRIVER_TYPE_D
;
mmc
->
caps
|=
MMC_CAP_DRIVER_TYPE_D
;
/* Initial value for re-tuning timer count */
/* Initial value for re-tuning timer count */
host
->
tuning_count
=
(
caps
[
1
]
&
SDHCI_RETUNING_TIMER_COUNT_MASK
)
>>
host
->
tuning_count
=
(
host
->
caps1
&
SDHCI_RETUNING_TIMER_COUNT_MASK
)
>>
SDHCI_RETUNING_TIMER_COUNT_SHIFT
;
SDHCI_RETUNING_TIMER_COUNT_SHIFT
;
/*
/*
...
@@ -3317,7 +3397,7 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3317,7 +3397,7 @@ int sdhci_add_host(struct sdhci_host *host)
host
->
tuning_count
=
1
<<
(
host
->
tuning_count
-
1
);
host
->
tuning_count
=
1
<<
(
host
->
tuning_count
-
1
);
/* Re-tuning mode supported by the Host Controller */
/* Re-tuning mode supported by the Host Controller */
host
->
tuning_mode
=
(
caps
[
1
]
&
SDHCI_RETUNING_MODE_MASK
)
>>
host
->
tuning_mode
=
(
host
->
caps1
&
SDHCI_RETUNING_MODE_MASK
)
>>
SDHCI_RETUNING_MODE_SHIFT
;
SDHCI_RETUNING_MODE_SHIFT
;
ocr_avail
=
0
;
ocr_avail
=
0
;
...
@@ -3346,7 +3426,7 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3346,7 +3426,7 @@ int sdhci_add_host(struct sdhci_host *host)
}
}
}
}
if
(
caps
[
0
]
&
SDHCI_CAN_VDD_330
)
{
if
(
host
->
caps
&
SDHCI_CAN_VDD_330
)
{
ocr_avail
|=
MMC_VDD_32_33
|
MMC_VDD_33_34
;
ocr_avail
|=
MMC_VDD_32_33
|
MMC_VDD_33_34
;
mmc
->
max_current_330
=
((
max_current_caps
&
mmc
->
max_current_330
=
((
max_current_caps
&
...
@@ -3354,7 +3434,7 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3354,7 +3434,7 @@ int sdhci_add_host(struct sdhci_host *host)
SDHCI_MAX_CURRENT_330_SHIFT
)
*
SDHCI_MAX_CURRENT_330_SHIFT
)
*
SDHCI_MAX_CURRENT_MULTIPLIER
;
SDHCI_MAX_CURRENT_MULTIPLIER
;
}
}
if
(
caps
[
0
]
&
SDHCI_CAN_VDD_300
)
{
if
(
host
->
caps
&
SDHCI_CAN_VDD_300
)
{
ocr_avail
|=
MMC_VDD_29_30
|
MMC_VDD_30_31
;
ocr_avail
|=
MMC_VDD_29_30
|
MMC_VDD_30_31
;
mmc
->
max_current_300
=
((
max_current_caps
&
mmc
->
max_current_300
=
((
max_current_caps
&
...
@@ -3362,7 +3442,7 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3362,7 +3442,7 @@ int sdhci_add_host(struct sdhci_host *host)
SDHCI_MAX_CURRENT_300_SHIFT
)
*
SDHCI_MAX_CURRENT_300_SHIFT
)
*
SDHCI_MAX_CURRENT_MULTIPLIER
;
SDHCI_MAX_CURRENT_MULTIPLIER
;
}
}
if
(
caps
[
0
]
&
SDHCI_CAN_VDD_180
)
{
if
(
host
->
caps
&
SDHCI_CAN_VDD_180
)
{
ocr_avail
|=
MMC_VDD_165_195
;
ocr_avail
|=
MMC_VDD_165_195
;
mmc
->
max_current_180
=
((
max_current_caps
&
mmc
->
max_current_180
=
((
max_current_caps
&
...
@@ -3371,13 +3451,14 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3371,13 +3451,14 @@ int sdhci_add_host(struct sdhci_host *host)
SDHCI_MAX_CURRENT_MULTIPLIER
;
SDHCI_MAX_CURRENT_MULTIPLIER
;
}
}
/* If OCR set by external regulators, use it instead */
/* If OCR set by host, use it instead. */
if
(
host
->
ocr_mask
)
ocr_avail
=
host
->
ocr_mask
;
/* If OCR set by external regulators, give it highest prio. */
if
(
mmc
->
ocr_avail
)
if
(
mmc
->
ocr_avail
)
ocr_avail
=
mmc
->
ocr_avail
;
ocr_avail
=
mmc
->
ocr_avail
;
if
(
host
->
ocr_mask
)
ocr_avail
&=
host
->
ocr_mask
;
mmc
->
ocr_avail
=
ocr_avail
;
mmc
->
ocr_avail
=
ocr_avail
;
mmc
->
ocr_avail_sdio
=
ocr_avail
;
mmc
->
ocr_avail_sdio
=
ocr_avail
;
if
(
host
->
ocr_avail_sdio
)
if
(
host
->
ocr_avail_sdio
)
...
@@ -3392,11 +3473,21 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3392,11 +3473,21 @@ int sdhci_add_host(struct sdhci_host *host)
mmc
->
ocr_avail_mmc
&=
host
->
ocr_avail_mmc
;
mmc
->
ocr_avail_mmc
&=
host
->
ocr_avail_mmc
;
if
(
mmc
->
ocr_avail
==
0
)
{
if
(
mmc
->
ocr_avail
==
0
)
{
pr_err
(
"%s: Hardware doesn't report any "
pr_err
(
"%s: Hardware doesn't report any support voltages.
\n
"
,
"support voltages.
\n
"
,
mmc_hostname
(
mmc
));
mmc_hostname
(
mmc
));
return
-
ENODEV
;
ret
=
-
ENODEV
;
goto
unreg
;
}
}
if
((
mmc
->
caps
&
(
MMC_CAP_UHS_SDR12
|
MMC_CAP_UHS_SDR25
|
MMC_CAP_UHS_SDR50
|
MMC_CAP_UHS_SDR104
|
MMC_CAP_UHS_DDR50
|
MMC_CAP_1_8V_DDR
))
||
(
mmc
->
caps2
&
(
MMC_CAP2_HS200_1_8V_SDR
|
MMC_CAP2_HS400_1_8V
)))
host
->
flags
|=
SDHCI_SIGNALING_180
;
if
(
mmc
->
caps2
&
MMC_CAP2_HSX00_1_2V
)
host
->
flags
|=
SDHCI_SIGNALING_120
;
spin_lock_init
(
&
host
->
lock
);
spin_lock_init
(
&
host
->
lock
);
/*
/*
...
@@ -3438,7 +3529,7 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3438,7 +3529,7 @@ int sdhci_add_host(struct sdhci_host *host)
if
(
host
->
quirks
&
SDHCI_QUIRK_FORCE_BLK_SZ_2048
)
{
if
(
host
->
quirks
&
SDHCI_QUIRK_FORCE_BLK_SZ_2048
)
{
mmc
->
max_blk_size
=
2
;
mmc
->
max_blk_size
=
2
;
}
else
{
}
else
{
mmc
->
max_blk_size
=
(
caps
[
0
]
&
SDHCI_MAX_BLOCK_MASK
)
>>
mmc
->
max_blk_size
=
(
host
->
caps
&
SDHCI_MAX_BLOCK_MASK
)
>>
SDHCI_MAX_BLOCK_SHIFT
;
SDHCI_MAX_BLOCK_SHIFT
;
if
(
mmc
->
max_blk_size
>=
3
)
{
if
(
mmc
->
max_blk_size
>=
3
)
{
pr_warn
(
"%s: Invalid maximum block size, assuming 512 bytes
\n
"
,
pr_warn
(
"%s: Invalid maximum block size, assuming 512 bytes
\n
"
,
...
@@ -3454,6 +3545,28 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3454,6 +3545,28 @@ int sdhci_add_host(struct sdhci_host *host)
*/
*/
mmc
->
max_blk_count
=
(
host
->
quirks
&
SDHCI_QUIRK_NO_MULTIBLOCK
)
?
1
:
65535
;
mmc
->
max_blk_count
=
(
host
->
quirks
&
SDHCI_QUIRK_NO_MULTIBLOCK
)
?
1
:
65535
;
return
0
;
unreg:
if
(
!
IS_ERR
(
mmc
->
supply
.
vqmmc
))
regulator_disable
(
mmc
->
supply
.
vqmmc
);
undma:
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_setup_host
);
int
__sdhci_add_host
(
struct
sdhci_host
*
host
)
{
struct
mmc_host
*
mmc
=
host
->
mmc
;
int
ret
;
/*
/*
* Init tasklets.
* Init tasklets.
*/
*/
...
@@ -3461,16 +3574,11 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3461,16 +3574,11 @@ int sdhci_add_host(struct sdhci_host *host)
sdhci_tasklet_finish
,
(
unsigned
long
)
host
);
sdhci_tasklet_finish
,
(
unsigned
long
)
host
);
setup_timer
(
&
host
->
timer
,
sdhci_timeout_timer
,
(
unsigned
long
)
host
);
setup_timer
(
&
host
->
timer
,
sdhci_timeout_timer
,
(
unsigned
long
)
host
);
setup_timer
(
&
host
->
data_timer
,
sdhci_timeout_data_timer
,
(
unsigned
long
)
host
);
init_waitqueue_head
(
&
host
->
buf_ready_int
);
init_waitqueue_head
(
&
host
->
buf_ready_int
);
if
(
host
->
version
>=
SDHCI_SPEC_300
)
{
/* Initialize re-tuning timer */
init_timer
(
&
host
->
tuning_timer
);
host
->
tuning_timer
.
data
=
(
unsigned
long
)
host
;
host
->
tuning_timer
.
function
=
sdhci_tuning_timer
;
}
sdhci_init
(
host
,
0
);
sdhci_init
(
host
,
0
);
ret
=
request_threaded_irq
(
host
->
irq
,
sdhci_irq
,
sdhci_thread_irq
,
ret
=
request_threaded_irq
(
host
->
irq
,
sdhci_irq
,
sdhci_thread_irq
,
...
@@ -3485,25 +3593,18 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3485,25 +3593,18 @@ int sdhci_add_host(struct sdhci_host *host)
sdhci_dumpregs
(
host
);
sdhci_dumpregs
(
host
);
#endif
#endif
#ifdef SDHCI_USE_LEDS_CLASS
ret
=
sdhci_led_register
(
host
);
snprintf
(
host
->
led_name
,
sizeof
(
host
->
led_name
),
"%s::"
,
mmc_hostname
(
mmc
));
host
->
led
.
name
=
host
->
led_name
;
host
->
led
.
brightness
=
LED_OFF
;
host
->
led
.
default_trigger
=
mmc_hostname
(
mmc
);
host
->
led
.
brightness_set
=
sdhci_led_control
;
ret
=
led_classdev_register
(
mmc_dev
(
mmc
),
&
host
->
led
);
if
(
ret
)
{
if
(
ret
)
{
pr_err
(
"%s: Failed to register LED device: %d
\n
"
,
pr_err
(
"%s: Failed to register LED device: %d
\n
"
,
mmc_hostname
(
mmc
),
ret
);
mmc_hostname
(
mmc
),
ret
);
goto
reset
;
goto
unirq
;
}
}
#endif
mmiowb
();
mmiowb
();
mmc_add_host
(
mmc
);
ret
=
mmc_add_host
(
mmc
);
if
(
ret
)
goto
unled
;
pr_info
(
"%s: SDHCI controller on %s [%s] using %s
\n
"
,
pr_info
(
"%s: SDHCI controller on %s [%s] using %s
\n
"
,
mmc_hostname
(
mmc
),
host
->
hw_name
,
dev_name
(
mmc_dev
(
mmc
)),
mmc_hostname
(
mmc
),
host
->
hw_name
,
dev_name
(
mmc_dev
(
mmc
)),
...
@@ -3515,19 +3616,40 @@ int sdhci_add_host(struct sdhci_host *host)
...
@@ -3515,19 +3616,40 @@ int sdhci_add_host(struct sdhci_host *host)
return
0
;
return
0
;
#ifdef SDHCI_USE_LEDS_CLASS
unled:
reset:
sdhci_led_unregister
(
host
);
unirq:
sdhci_do_reset
(
host
,
SDHCI_RESET_ALL
);
sdhci_do_reset
(
host
,
SDHCI_RESET_ALL
);
sdhci_writel
(
host
,
0
,
SDHCI_INT_ENABLE
);
sdhci_writel
(
host
,
0
,
SDHCI_INT_ENABLE
);
sdhci_writel
(
host
,
0
,
SDHCI_SIGNAL_ENABLE
);
sdhci_writel
(
host
,
0
,
SDHCI_SIGNAL_ENABLE
);
free_irq
(
host
->
irq
,
host
);
free_irq
(
host
->
irq
,
host
);
#endif
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
);
int
sdhci_add_host
(
struct
sdhci_host
*
host
)
{
int
ret
;
ret
=
sdhci_setup_host
(
host
);
if
(
ret
)
return
ret
;
return
__sdhci_add_host
(
host
);
}
EXPORT_SYMBOL_GPL
(
sdhci_add_host
);
EXPORT_SYMBOL_GPL
(
sdhci_add_host
);
void
sdhci_remove_host
(
struct
sdhci_host
*
host
,
int
dead
)
void
sdhci_remove_host
(
struct
sdhci_host
*
host
,
int
dead
)
...
@@ -3540,12 +3662,10 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
...
@@ -3540,12 +3662,10 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
host
->
flags
|=
SDHCI_DEVICE_DEAD
;
host
->
flags
|=
SDHCI_DEVICE_DEAD
;
if
(
host
->
mrq
)
{
if
(
sdhci_has_requests
(
host
)
)
{
pr_err
(
"%s: Controller removed during "
pr_err
(
"%s: Controller removed during "
" transfer!
\n
"
,
mmc_hostname
(
mmc
));
" transfer!
\n
"
,
mmc_hostname
(
mmc
));
sdhci_error_out_mrqs
(
host
,
-
ENOMEDIUM
);
host
->
mrq
->
cmd
->
error
=
-
ENOMEDIUM
;
tasklet_schedule
(
&
host
->
finish_tasklet
);
}
}
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
...
@@ -3555,9 +3675,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
...
@@ -3555,9 +3675,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
mmc_remove_host
(
mmc
);
mmc_remove_host
(
mmc
);
#ifdef SDHCI_USE_LEDS_CLASS
sdhci_led_unregister
(
host
);
led_classdev_unregister
(
&
host
->
led
);
#endif
if
(
!
dead
)
if
(
!
dead
)
sdhci_do_reset
(
host
,
SDHCI_RESET_ALL
);
sdhci_do_reset
(
host
,
SDHCI_RESET_ALL
);
...
@@ -3567,16 +3685,17 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
...
@@ -3567,16 +3685,17 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
free_irq
(
host
->
irq
,
host
);
free_irq
(
host
->
irq
,
host
);
del_timer_sync
(
&
host
->
timer
);
del_timer_sync
(
&
host
->
timer
);
del_timer_sync
(
&
host
->
data_timer
);
tasklet_kill
(
&
host
->
finish_tasklet
);
tasklet_kill
(
&
host
->
finish_tasklet
);
if
(
!
IS_ERR
(
mmc
->
supply
.
vqmmc
))
if
(
!
IS_ERR
(
mmc
->
supply
.
vqmmc
))
regulator_disable
(
mmc
->
supply
.
vqmmc
);
regulator_disable
(
mmc
->
supply
.
vqmmc
);
if
(
host
->
a
dma_table
)
if
(
host
->
a
lign_buffer
)
dma_free_coherent
(
mmc_dev
(
mmc
),
host
->
a
dma_table_sz
,
dma_free_coherent
(
mmc_dev
(
mmc
),
host
->
a
lign_buffer_sz
+
host
->
adma_table
,
host
->
adma_addr
);
host
->
adma_table
_sz
,
host
->
align_buffer
,
kfree
(
host
->
align_buffe
r
);
host
->
align_add
r
);
host
->
adma_table
=
NULL
;
host
->
adma_table
=
NULL
;
host
->
align_buffer
=
NULL
;
host
->
align_buffer
=
NULL
;
...
...
src/drivers/mmc/host/sdhci.h
View file @
fb001670
...
@@ -18,7 +18,7 @@
...
@@ -18,7 +18,7 @@
#include <linux/types.h>
#include <linux/types.h>
#include <linux/io.h>
#include <linux/io.h>
#include <linux/mmc/
sdhci
.h>
#include <linux/mmc/
host
.h>
/*
/*
* Controller registers
* Controller registers
...
@@ -69,13 +69,15 @@
...
@@ -69,13 +69,15 @@
#define SDHCI_SPACE_AVAILABLE 0x00000400
#define SDHCI_SPACE_AVAILABLE 0x00000400
#define SDHCI_DATA_AVAILABLE 0x00000800
#define SDHCI_DATA_AVAILABLE 0x00000800
#define SDHCI_CARD_PRESENT 0x00010000
#define SDHCI_CARD_PRESENT 0x00010000
// Elphel: For 10393 rev.B unreliable D3 detection
#define SDHCI_DAT3_PRESENT 0x00800000
#define SDHCI_DAT3_PRESENT 0x00800000
//
For 10393 rev.B unreliable D3 detection
//
Elphel
#define SDHCI_ANY_PRESENT (SDHCI_CARD_PRESENT | SDHCI_DAT3_PRESENT)
#define SDHCI_ANY_PRESENT (SDHCI_CARD_PRESENT | SDHCI_DAT3_PRESENT)
#define SDHCI_WRITE_PROTECT 0x00080000
#define SDHCI_WRITE_PROTECT 0x00080000
#define SDHCI_DATA_LVL_MASK 0x00F00000
#define SDHCI_DATA_LVL_MASK 0x00F00000
#define SDHCI_DATA_LVL_SHIFT 20
#define SDHCI_DATA_LVL_SHIFT 20
#define SDHCI_DATA_0_LVL_MASK 0x00100000
#define SDHCI_DATA_0_LVL_MASK 0x00100000
#define SDHCI_CMD_LVL 0x01000000
#define SDHCI_HOST_CONTROL 0x28
#define SDHCI_HOST_CONTROL 0x28
#define SDHCI_CTRL_LED 0x01
#define SDHCI_CTRL_LED 0x01
...
@@ -87,6 +89,8 @@
...
@@ -87,6 +89,8 @@
#define SDHCI_CTRL_ADMA32 0x10
#define SDHCI_CTRL_ADMA32 0x10
#define SDHCI_CTRL_ADMA64 0x18
#define SDHCI_CTRL_ADMA64 0x18
#define SDHCI_CTRL_8BITBUS 0x20
#define SDHCI_CTRL_8BITBUS 0x20
#define SDHCI_CTRL_CDTEST_INS 0x40
#define SDHCI_CTRL_CDTEST_EN 0x80
#define SDHCI_POWER_CONTROL 0x29
#define SDHCI_POWER_CONTROL 0x29
#define SDHCI_POWER_ON 0x01
#define SDHCI_POWER_ON 0x01
...
@@ -131,6 +135,7 @@
...
@@ -131,6 +135,7 @@
#define SDHCI_INT_CARD_INSERT 0x00000040
#define SDHCI_INT_CARD_INSERT 0x00000040
#define SDHCI_INT_CARD_REMOVE 0x00000080
#define SDHCI_INT_CARD_REMOVE 0x00000080
#define SDHCI_INT_CARD_INT 0x00000100
#define SDHCI_INT_CARD_INT 0x00000100
#define SDHCI_INT_RETUNE 0x00001000
#define SDHCI_INT_ERROR 0x00008000
#define SDHCI_INT_ERROR 0x00008000
#define SDHCI_INT_TIMEOUT 0x00010000
#define SDHCI_INT_TIMEOUT 0x00010000
#define SDHCI_INT_CRC 0x00020000
#define SDHCI_INT_CRC 0x00020000
...
@@ -189,6 +194,7 @@
...
@@ -189,6 +194,7 @@
#define SDHCI_CAN_DO_ADMA1 0x00100000
#define SDHCI_CAN_DO_ADMA1 0x00100000
#define SDHCI_CAN_DO_HISPD 0x00200000
#define SDHCI_CAN_DO_HISPD 0x00200000
#define SDHCI_CAN_DO_SDMA 0x00400000
#define SDHCI_CAN_DO_SDMA 0x00400000
#define SDHCI_CAN_DO_SUSPEND 0x00800000
#define SDHCI_CAN_VDD_330 0x01000000
#define SDHCI_CAN_VDD_330 0x01000000
#define SDHCI_CAN_VDD_300 0x02000000
#define SDHCI_CAN_VDD_300 0x02000000
#define SDHCI_CAN_VDD_180 0x04000000
#define SDHCI_CAN_VDD_180 0x04000000
...
@@ -275,22 +281,27 @@
...
@@ -275,22 +281,27 @@
/* ADMA2 32-bit DMA descriptor size */
/* ADMA2 32-bit DMA descriptor size */
#define SDHCI_ADMA2_32_DESC_SZ 8
#define SDHCI_ADMA2_32_DESC_SZ 8
/* ADMA2 32-bit DMA alignment */
#define SDHCI_ADMA2_32_ALIGN 4
/* ADMA2 32-bit descriptor */
/* ADMA2 32-bit descriptor */
struct
sdhci_adma2_32_desc
{
struct
sdhci_adma2_32_desc
{
__le16
cmd
;
__le16
cmd
;
__le16
len
;
__le16
len
;
__le32
addr
;
__le32
addr
;
}
__packed
__aligned
(
SDHCI_ADMA2_32_ALIGN
);
}
__packed
__aligned
(
4
);
/* ADMA2 data alignment */
#define SDHCI_ADMA2_ALIGN 4
#define SDHCI_ADMA2_MASK (SDHCI_ADMA2_ALIGN - 1)
/*
* ADMA2 descriptor alignment. Some controllers (e.g. Intel) require 8 byte
* alignment for the descriptor table even in 32-bit DMA mode. Memory
* allocation is at least 8 byte aligned anyway, so just stipulate 8 always.
*/
#define SDHCI_ADMA2_DESC_ALIGN 8
/* ADMA2 64-bit DMA descriptor size */
/* ADMA2 64-bit DMA descriptor size */
#define SDHCI_ADMA2_64_DESC_SZ 12
#define SDHCI_ADMA2_64_DESC_SZ 12
/* ADMA2 64-bit DMA alignment */
#define SDHCI_ADMA2_64_ALIGN 8
/*
/*
* ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte
* ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte
* aligned.
* aligned.
...
@@ -312,6 +323,217 @@ struct sdhci_adma2_64_desc {
...
@@ -312,6 +323,217 @@ struct sdhci_adma2_64_desc {
*/
*/
#define SDHCI_MAX_SEGS 128
#define SDHCI_MAX_SEGS 128
/* Allow for a a command request and a data request at the same time */
#define SDHCI_MAX_MRQS 2
enum
sdhci_cookie
{
COOKIE_UNMAPPED
,
COOKIE_PRE_MAPPED
,
/* mapped by sdhci_pre_req() */
COOKIE_MAPPED
,
/* mapped by sdhci_prepare_data() */
};
struct
sdhci_host
{
/* Data set by hardware interface driver */
const
char
*
hw_name
;
/* Hardware bus name */
unsigned
int
quirks
;
/* Deviations from spec. */
/* Controller doesn't honor resets unless we touch the clock register */
#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0)
/* Controller has bad caps bits, but really supports DMA */
#define SDHCI_QUIRK_FORCE_DMA (1<<1)
/* Controller doesn't like to be reset when there is no card inserted. */
#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2)
/* Controller doesn't like clearing the power reg before a change */
#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3)
/* Controller has flaky internal state so reset it on each ios change */
#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4)
/* Controller has an unusable DMA engine */
#define SDHCI_QUIRK_BROKEN_DMA (1<<5)
/* Controller has an unusable ADMA engine */
#define SDHCI_QUIRK_BROKEN_ADMA (1<<6)
/* Controller can only DMA from 32-bit aligned addresses */
#define SDHCI_QUIRK_32BIT_DMA_ADDR (1<<7)
/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
#define SDHCI_QUIRK_32BIT_DMA_SIZE (1<<8)
/* Controller can only ADMA chunks that are a multiple of 32 bits */
#define SDHCI_QUIRK_32BIT_ADMA_SIZE (1<<9)
/* Controller needs to be reset after each request to stay stable */
#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<10)
/* Controller needs voltage and power writes to happen separately */
#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1<<11)
/* Controller provides an incorrect timeout value for transfers */
#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL (1<<12)
/* Controller has an issue with buffer bits for small transfers */
#define SDHCI_QUIRK_BROKEN_SMALL_PIO (1<<13)
/* Controller does not provide transfer-complete interrupt when not busy */
#define SDHCI_QUIRK_NO_BUSY_IRQ (1<<14)
/* Controller has unreliable card detection */
#define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1<<15)
/* Controller reports inverted write-protect state */
#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1<<16)
/* Controller does not like fast PIO transfers */
#define SDHCI_QUIRK_PIO_NEEDS_DELAY (1<<18)
/* Controller has to be forced to use block size of 2048 bytes */
#define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20)
/* Controller cannot do multi-block transfers */
#define SDHCI_QUIRK_NO_MULTIBLOCK (1<<21)
/* Controller can only handle 1-bit data transfers */
#define SDHCI_QUIRK_FORCE_1_BIT_DATA (1<<22)
/* Controller needs 10ms delay between applying power and clock */
#define SDHCI_QUIRK_DELAY_AFTER_POWER (1<<23)
/* Controller uses SDCLK instead of TMCLK for data timeouts */
#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK (1<<24)
/* Controller reports wrong base clock capability */
#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN (1<<25)
/* Controller cannot support End Attribute in NOP ADMA descriptor */
#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC (1<<26)
/* Controller is missing device caps. Use caps provided by host */
#define SDHCI_QUIRK_MISSING_CAPS (1<<27)
/* Controller uses Auto CMD12 command to stop the transfer */
#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 (1<<28)
/* Controller doesn't have HISPD bit field in HI-SPEED SD card */
#define SDHCI_QUIRK_NO_HISPD_BIT (1<<29)
/* Controller treats ADMA descriptors with length 0000h incorrectly */
#define SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC (1<<30)
/* The read-only detection via SDHCI_PRESENT_STATE register is unstable */
#define SDHCI_QUIRK_UNSTABLE_RO_DETECT (1<<31)
unsigned
int
quirks2
;
/* More deviations from spec. */
#define SDHCI_QUIRK2_HOST_OFF_CARD_ON (1<<0)
#define SDHCI_QUIRK2_HOST_NO_CMD23 (1<<1)
/* The system physically doesn't support 1.8v, even if the host does */
#define SDHCI_QUIRK2_NO_1_8_V (1<<2)
#define SDHCI_QUIRK2_PRESET_VALUE_BROKEN (1<<3)
#define SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON (1<<4)
/* Controller has a non-standard host control register */
#define SDHCI_QUIRK2_BROKEN_HOST_CONTROL (1<<5)
/* Controller does not support HS200 */
#define SDHCI_QUIRK2_BROKEN_HS200 (1<<6)
/* Controller does not support DDR50 */
#define SDHCI_QUIRK2_BROKEN_DDR50 (1<<7)
/* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */
#define SDHCI_QUIRK2_STOP_WITH_TC (1<<8)
/* Controller does not support 64-bit DMA */
#define SDHCI_QUIRK2_BROKEN_64_BIT_DMA (1<<9)
/* need clear transfer mode register before send cmd */
#define SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD (1<<10)
/* Capability register bit-63 indicates HS400 support */
#define SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 (1<<11)
/* forced tuned clock */
#define SDHCI_QUIRK2_TUNING_WORK_AROUND (1<<12)
/* disable the block count for single block transactions */
#define SDHCI_QUIRK2_SUPPORT_SINGLE (1<<13)
/* Controller broken with using ACMD23 */
#define SDHCI_QUIRK2_ACMD23_BROKEN (1<<14)
/* Broken Clock divider zero in controller */
#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1<<15)
/* Broken Clock between 19MHz-25MHz */
#define SDHCI_QUIRK2_CLOCK_STANDARD_25_BROKEN (1<<16)
int
irq
;
/* Device IRQ */
void
__iomem
*
ioaddr
;
/* Mapped address */
const
struct
sdhci_ops
*
ops
;
/* Low level hw interface */
/* Internal data */
struct
mmc_host
*
mmc
;
/* MMC structure */
struct
mmc_host_ops
mmc_host_ops
;
/* MMC host ops */
u64
dma_mask
;
/* custom DMA mask */
#if IS_ENABLED(CONFIG_LEDS_CLASS)
struct
led_classdev
led
;
/* LED control */
char
led_name
[
32
];
#endif
spinlock_t
lock
;
/* Mutex */
int
flags
;
/* Host attributes */
#define SDHCI_USE_SDMA (1<<0)
/* Host is SDMA capable */
#define SDHCI_USE_ADMA (1<<1)
/* Host is ADMA capable */
#define SDHCI_REQ_USE_DMA (1<<2)
/* Use DMA for this req. */
#define SDHCI_DEVICE_DEAD (1<<3)
/* Device unresponsive */
#define SDHCI_SDR50_NEEDS_TUNING (1<<4)
/* SDR50 needs tuning */
#define SDHCI_AUTO_CMD12 (1<<6)
/* Auto CMD12 support */
#define SDHCI_AUTO_CMD23 (1<<7)
/* Auto CMD23 support */
#define SDHCI_PV_ENABLED (1<<8)
/* Preset value enabled */
#define SDHCI_SDIO_IRQ_ENABLED (1<<9)
/* SDIO irq enabled */
#define SDHCI_USE_64_BIT_DMA (1<<12)
/* Use 64-bit DMA */
#define SDHCI_HS400_TUNING (1<<13)
/* Tuning for HS400 */
#define SDHCI_SIGNALING_330 (1<<14)
/* Host is capable of 3.3V signaling */
#define SDHCI_SIGNALING_180 (1<<15)
/* Host is capable of 1.8V signaling */
#define SDHCI_SIGNALING_120 (1<<16)
/* Host is capable of 1.2V signaling */
unsigned
int
version
;
/* SDHCI spec. version */
unsigned
int
max_clk
;
/* Max possible freq (MHz) */
unsigned
int
timeout_clk
;
/* Timeout freq (KHz) */
unsigned
int
clk_mul
;
/* Clock Muliplier value */
unsigned
int
clock
;
/* Current clock (MHz) */
u8
pwr
;
/* Current voltage */
bool
runtime_suspended
;
/* Host is runtime suspended */
bool
bus_on
;
/* Bus power prevents runtime suspend */
bool
preset_enabled
;
/* Preset is enabled */
bool
pending_reset
;
/* Cmd/data reset is pending */
struct
mmc_request
*
mrqs_done
[
SDHCI_MAX_MRQS
];
/* Requests done */
struct
mmc_command
*
cmd
;
/* Current command */
struct
mmc_command
*
data_cmd
;
/* Current data command */
struct
mmc_data
*
data
;
/* Current data request */
unsigned
int
data_early
:
1
;
/* Data finished before cmd */
struct
sg_mapping_iter
sg_miter
;
/* SG state for PIO */
unsigned
int
blocks
;
/* remaining PIO blocks */
int
sg_count
;
/* Mapped sg entries */
void
*
adma_table
;
/* ADMA descriptor table */
void
*
align_buffer
;
/* Bounce buffer */
size_t
adma_table_sz
;
/* ADMA descriptor table size */
size_t
align_buffer_sz
;
/* Bounce buffer size */
dma_addr_t
adma_addr
;
/* Mapped ADMA descr. table */
dma_addr_t
align_addr
;
/* Mapped bounce buffer */
unsigned
int
desc_sz
;
/* ADMA descriptor size */
struct
tasklet_struct
finish_tasklet
;
/* Tasklet structures */
struct
timer_list
timer
;
/* Timer for timeouts */
struct
timer_list
data_timer
;
/* Timer for data timeouts */
u32
caps
;
/* CAPABILITY_0 */
u32
caps1
;
/* CAPABILITY_1 */
bool
read_caps
;
/* Capability flags have been read */
unsigned
int
ocr_avail_sdio
;
/* OCR bit masks */
unsigned
int
ocr_avail_sd
;
unsigned
int
ocr_avail_mmc
;
u32
ocr_mask
;
/* available voltages */
unsigned
timing
;
/* Current timing */
u32
thread_isr
;
/* cached registers */
u32
ier
;
wait_queue_head_t
buf_ready_int
;
/* Waitqueue for Buffer Read Ready interrupt */
unsigned
int
tuning_done
;
/* Condition flag set when CMD19 succeeds */
unsigned
int
tuning_count
;
/* Timer count for re-tuning */
unsigned
int
tuning_mode
;
/* Re-tuning mode supported by host */
#define SDHCI_TUNING_MODE_1 0
#define SDHCI_TUNING_MODE_2 1
#define SDHCI_TUNING_MODE_3 2
unsigned
long
private
[
0
]
____cacheline_aligned
;
};
struct
sdhci_ops
{
struct
sdhci_ops
{
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
u32
(
*
read_l
)(
struct
sdhci_host
*
host
,
int
reg
);
u32
(
*
read_l
)(
struct
sdhci_host
*
host
,
int
reg
);
...
@@ -323,6 +545,8 @@ struct sdhci_ops {
...
@@ -323,6 +545,8 @@ struct sdhci_ops {
#endif
#endif
void
(
*
set_clock
)(
struct
sdhci_host
*
host
,
unsigned
int
clock
);
void
(
*
set_clock
)(
struct
sdhci_host
*
host
,
unsigned
int
clock
);
void
(
*
set_power
)(
struct
sdhci_host
*
host
,
unsigned
char
mode
,
unsigned
short
vdd
);
int
(
*
enable_dma
)(
struct
sdhci_host
*
host
);
int
(
*
enable_dma
)(
struct
sdhci_host
*
host
);
unsigned
int
(
*
get_max_clock
)(
struct
sdhci_host
*
host
);
unsigned
int
(
*
get_max_clock
)(
struct
sdhci_host
*
host
);
...
@@ -340,9 +564,12 @@ struct sdhci_ops {
...
@@ -340,9 +564,12 @@ struct sdhci_ops {
void
(
*
set_uhs_signaling
)(
struct
sdhci_host
*
host
,
unsigned
int
uhs
);
void
(
*
set_uhs_signaling
)(
struct
sdhci_host
*
host
,
unsigned
int
uhs
);
void
(
*
hw_reset
)(
struct
sdhci_host
*
host
);
void
(
*
hw_reset
)(
struct
sdhci_host
*
host
);
void
(
*
adma_workaround
)(
struct
sdhci_host
*
host
,
u32
intmask
);
void
(
*
adma_workaround
)(
struct
sdhci_host
*
host
,
u32
intmask
);
void
(
*
platform_init
)(
struct
sdhci_host
*
host
);
void
(
*
card_event
)(
struct
sdhci_host
*
host
);
void
(
*
card_event
)(
struct
sdhci_host
*
host
);
void
(
*
voltage_switch
)(
struct
sdhci_host
*
host
);
void
(
*
voltage_switch
)(
struct
sdhci_host
*
host
);
int
(
*
select_drive_strength
)(
struct
sdhci_host
*
host
,
struct
mmc_card
*
card
,
unsigned
int
max_dtr
,
int
host_drv
,
int
card_drv
,
int
*
drv_type
);
};
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
...
@@ -439,17 +666,32 @@ static inline void *sdhci_priv(struct sdhci_host *host)
...
@@ -439,17 +666,32 @@ static inline void *sdhci_priv(struct sdhci_host *host)
}
}
extern
void
sdhci_card_detect
(
struct
sdhci_host
*
host
);
extern
void
sdhci_card_detect
(
struct
sdhci_host
*
host
);
extern
void
__sdhci_read_caps
(
struct
sdhci_host
*
host
,
u16
*
ver
,
u32
*
caps
,
u32
*
caps1
);
extern
int
sdhci_setup_host
(
struct
sdhci_host
*
host
);
extern
int
__sdhci_add_host
(
struct
sdhci_host
*
host
);
extern
int
sdhci_add_host
(
struct
sdhci_host
*
host
);
extern
int
sdhci_add_host
(
struct
sdhci_host
*
host
);
extern
void
sdhci_remove_host
(
struct
sdhci_host
*
host
,
int
dead
);
extern
void
sdhci_remove_host
(
struct
sdhci_host
*
host
,
int
dead
);
extern
void
sdhci_send_command
(
struct
sdhci_host
*
host
,
extern
void
sdhci_send_command
(
struct
sdhci_host
*
host
,
struct
mmc_command
*
cmd
);
struct
mmc_command
*
cmd
);
static
inline
void
sdhci_read_caps
(
struct
sdhci_host
*
host
)
{
__sdhci_read_caps
(
host
,
NULL
,
NULL
,
NULL
);
}
static
inline
bool
sdhci_sdio_irq_enabled
(
struct
sdhci_host
*
host
)
static
inline
bool
sdhci_sdio_irq_enabled
(
struct
sdhci_host
*
host
)
{
{
return
!!
(
host
->
flags
&
SDHCI_SDIO_IRQ_ENABLED
);
return
!!
(
host
->
flags
&
SDHCI_SDIO_IRQ_ENABLED
);
}
}
u16
sdhci_calc_clk
(
struct
sdhci_host
*
host
,
unsigned
int
clock
,
unsigned
int
*
actual_clock
);
void
sdhci_set_clock
(
struct
sdhci_host
*
host
,
unsigned
int
clock
);
void
sdhci_set_clock
(
struct
sdhci_host
*
host
,
unsigned
int
clock
);
void
sdhci_set_power
(
struct
sdhci_host
*
host
,
unsigned
char
mode
,
unsigned
short
vdd
);
void
sdhci_set_power_noreg
(
struct
sdhci_host
*
host
,
unsigned
char
mode
,
unsigned
short
vdd
);
void
sdhci_set_bus_width
(
struct
sdhci_host
*
host
,
int
width
);
void
sdhci_set_bus_width
(
struct
sdhci_host
*
host
,
int
width
);
void
sdhci_reset
(
struct
sdhci_host
*
host
,
u8
mask
);
void
sdhci_reset
(
struct
sdhci_host
*
host
,
u8
mask
);
void
sdhci_set_uhs_signaling
(
struct
sdhci_host
*
host
,
unsigned
timing
);
void
sdhci_set_uhs_signaling
(
struct
sdhci_host
*
host
,
unsigned
timing
);
...
...
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