Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
bba1594d
K
Kernel
项目概览
openeuler
/
Kernel
大约 1 年 前同步成功
通知
5
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
bba1594d
编写于
3月 24, 2012
作者:
R
Russell King
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'mmci' into amba
上级
9e5ed094
7437cfa5
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
151 addition
and
73 deletion
+151
-73
arch/arm/mach-ux500/board-mop500-sdi.c
arch/arm/mach-ux500/board-mop500-sdi.c
+8
-13
drivers/mmc/host/mmci.c
drivers/mmc/host/mmci.c
+121
-45
drivers/mmc/host/mmci.h
drivers/mmc/host/mmci.h
+3
-12
include/linux/amba/mmci.h
include/linux/amba/mmci.h
+19
-3
未找到文件。
arch/arm/mach-ux500/board-mop500-sdi.c
浏览文件 @
bba1594d
...
...
@@ -31,21 +31,13 @@
* SDI 0 (MicroSD slot)
*/
/* MMCIPOWER bits */
#define MCI_DATA2DIREN (1 << 2)
#define MCI_CMDDIREN (1 << 3)
#define MCI_DATA0DIREN (1 << 4)
#define MCI_DATA31DIREN (1 << 5)
#define MCI_FBCLKEN (1 << 7)
/* GPIO pins used by the sdi0 level shifter */
static
int
sdi0_en
=
-
1
;
static
int
sdi0_vsel
=
-
1
;
static
u32
mop500_sdi0_vdd_handler
(
struct
device
*
dev
,
unsigned
int
vdd
,
unsigned
char
power_mode
)
static
int
mop500_sdi0_ios_handler
(
struct
device
*
dev
,
struct
mmc_ios
*
ios
)
{
switch
(
power_mode
)
{
switch
(
ios
->
power_mode
)
{
case
MMC_POWER_UP
:
case
MMC_POWER_ON
:
/*
...
...
@@ -65,8 +57,7 @@ static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd,
break
;
}
return
MCI_FBCLKEN
|
MCI_CMDDIREN
|
MCI_DATA0DIREN
|
MCI_DATA2DIREN
|
MCI_DATA31DIREN
;
return
0
;
}
#ifdef CONFIG_STE_DMA40
...
...
@@ -90,13 +81,17 @@ static struct stedma40_chan_cfg mop500_sdi0_dma_cfg_tx = {
#endif
static
struct
mmci_platform_data
mop500_sdi0_data
=
{
.
vdd_handler
=
mop500_sdi0_vdd
_handler
,
.
ios_handler
=
mop500_sdi0_ios
_handler
,
.
ocr_mask
=
MMC_VDD_29_30
,
.
f_max
=
50000000
,
.
capabilities
=
MMC_CAP_4_BIT_DATA
|
MMC_CAP_SD_HIGHSPEED
|
MMC_CAP_MMC_HIGHSPEED
,
.
gpio_wp
=
-
1
,
.
sigdir
=
MCI_ST_FBCLKEN
|
MCI_ST_CMDDIREN
|
MCI_ST_DATA0DIREN
|
MCI_ST_DATA2DIREN
,
#ifdef CONFIG_STE_DMA40
.
dma_filter
=
stedma40_filter
,
.
dma_rx_param
=
&
mop500_sdi0_dma_cfg_rx
,
...
...
drivers/mmc/host/mmci.c
浏览文件 @
bba1594d
...
...
@@ -53,6 +53,8 @@ static unsigned int fmax = 515633;
* @sdio: variant supports SDIO
* @st_clkdiv: true if using a ST-specific clock divider algorithm
* @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
* @pwrreg_powerup: power up value for MMCIPOWER register
* @signal_direction: input/out direction of bus signals can be indicated
*/
struct
variant_data
{
unsigned
int
clkreg
;
...
...
@@ -63,18 +65,22 @@ struct variant_data {
bool
sdio
;
bool
st_clkdiv
;
bool
blksz_datactrl16
;
u32
pwrreg_powerup
;
bool
signal_direction
;
};
static
struct
variant_data
variant_arm
=
{
.
fifosize
=
16
*
4
,
.
fifohalfsize
=
8
*
4
,
.
datalength_bits
=
16
,
.
pwrreg_powerup
=
MCI_PWR_UP
,
};
static
struct
variant_data
variant_arm_extended_fifo
=
{
.
fifosize
=
128
*
4
,
.
fifohalfsize
=
64
*
4
,
.
datalength_bits
=
16
,
.
pwrreg_powerup
=
MCI_PWR_UP
,
};
static
struct
variant_data
variant_u300
=
{
...
...
@@ -83,6 +89,8 @@ static struct variant_data variant_u300 = {
.
clkreg_enable
=
MCI_ST_U300_HWFCEN
,
.
datalength_bits
=
16
,
.
sdio
=
true
,
.
pwrreg_powerup
=
MCI_PWR_ON
,
.
signal_direction
=
true
,
};
static
struct
variant_data
variant_ux500
=
{
...
...
@@ -93,6 +101,8 @@ static struct variant_data variant_ux500 = {
.
datalength_bits
=
24
,
.
sdio
=
true
,
.
st_clkdiv
=
true
,
.
pwrreg_powerup
=
MCI_PWR_ON
,
.
signal_direction
=
true
,
};
static
struct
variant_data
variant_ux500v2
=
{
...
...
@@ -104,8 +114,32 @@ static struct variant_data variant_ux500v2 = {
.
sdio
=
true
,
.
st_clkdiv
=
true
,
.
blksz_datactrl16
=
true
,
.
pwrreg_powerup
=
MCI_PWR_ON
,
.
signal_direction
=
true
,
};
/*
* This must be called with host->lock held
*/
static
void
mmci_write_clkreg
(
struct
mmci_host
*
host
,
u32
clk
)
{
if
(
host
->
clk_reg
!=
clk
)
{
host
->
clk_reg
=
clk
;
writel
(
clk
,
host
->
base
+
MMCICLOCK
);
}
}
/*
* This must be called with host->lock held
*/
static
void
mmci_write_pwrreg
(
struct
mmci_host
*
host
,
u32
pwr
)
{
if
(
host
->
pwr_reg
!=
pwr
)
{
host
->
pwr_reg
=
pwr
;
writel
(
pwr
,
host
->
base
+
MMCIPOWER
);
}
}
/*
* This must be called with host->lock held
*/
...
...
@@ -153,7 +187,7 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
if
(
host
->
mmc
->
ios
.
bus_width
==
MMC_BUS_WIDTH_8
)
clk
|=
MCI_ST_8BIT_BUS
;
writel
(
clk
,
host
->
base
+
MMCICLOCK
);
mmci_write_clkreg
(
host
,
clk
);
}
static
void
...
...
@@ -166,14 +200,10 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
host
->
mrq
=
NULL
;
host
->
cmd
=
NULL
;
/*
* Need to drop the host lock here; mmc_request_done may call
* back into the driver...
*/
spin_unlock
(
&
host
->
lock
);
pm_runtime_put
(
mmc_dev
(
host
->
mmc
));
mmc_request_done
(
host
->
mmc
,
mrq
);
spin_lock
(
&
host
->
lock
);
pm_runtime_mark_last_busy
(
mmc_dev
(
host
->
mmc
));
pm_runtime_put_autosuspend
(
mmc_dev
(
host
->
mmc
));
}
static
void
mmci_set_mask1
(
struct
mmci_host
*
host
,
unsigned
int
mask
)
...
...
@@ -607,6 +637,11 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
if
(
data
->
flags
&
MMC_DATA_READ
)
datactrl
|=
MCI_DPSM_DIRECTION
;
/* The ST Micro variants has a special bit to enable SDIO */
if
(
variant
->
sdio
&&
host
->
mmc
->
card
)
if
(
mmc_card_sdio
(
host
->
mmc
->
card
))
datactrl
|=
MCI_ST_DPSM_SDIOEN
;
/*
* Attempt to use DMA operation mode, if this
* should fail, fall back to PIO mode
...
...
@@ -635,11 +670,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
irqmask
=
MCI_TXFIFOHALFEMPTYMASK
;
}
/* The ST Micro variants has a special bit to enable SDIO */
if
(
variant
->
sdio
&&
host
->
mmc
->
card
)
if
(
mmc_card_sdio
(
host
->
mmc
->
card
))
datactrl
|=
MCI_ST_DPSM_SDIOEN
;
writel
(
datactrl
,
base
+
MMCIDATACTRL
);
writel
(
readl
(
base
+
MMCIMASK0
)
&
~
MCI_DATAENDMASK
,
base
+
MMCIMASK0
);
mmci_set_mask1
(
host
,
irqmask
);
...
...
@@ -786,7 +816,24 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema
if
(
count
<=
0
)
break
;
readsl
(
base
+
MMCIFIFO
,
ptr
,
count
>>
2
);
/*
* SDIO especially may want to send something that is
* not divisible by 4 (as opposed to card sectors
* etc). Therefore make sure to always read the last bytes
* while only doing full 32-bit reads towards the FIFO.
*/
if
(
unlikely
(
count
&
0x3
))
{
if
(
count
<
4
)
{
unsigned
char
buf
[
4
];
readsl
(
base
+
MMCIFIFO
,
buf
,
1
);
memcpy
(
ptr
,
buf
,
count
);
}
else
{
readsl
(
base
+
MMCIFIFO
,
ptr
,
count
>>
2
);
count
&=
~
0x3
;
}
}
else
{
readsl
(
base
+
MMCIFIFO
,
ptr
,
count
>>
2
);
}
ptr
+=
count
;
remain
-=
count
;
...
...
@@ -821,14 +868,13 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem
*/
if
(
variant
->
sdio
&&
mmc_card_sdio
(
host
->
mmc
->
card
))
{
u32
clk
;
if
(
count
<
8
)
writel
(
readl
(
host
->
base
+
MMCICLOCK
)
&
~
variant
->
clkreg_enable
,
host
->
base
+
MMCICLOCK
);
clk
=
host
->
clk_reg
&
~
variant
->
clkreg_enable
;
else
writel
(
readl
(
host
->
base
+
MMCICLOCK
)
|
variant
->
clkreg_enable
,
host
->
base
+
MMCICLOCK
);
clk
=
host
->
clk_reg
|
variant
->
clkreg_enable
;
mmci_write_clkreg
(
host
,
clk
);
}
/*
...
...
@@ -1015,10 +1061,17 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
static
void
mmci_set_ios
(
struct
mmc_host
*
mmc
,
struct
mmc_ios
*
ios
)
{
struct
mmci_host
*
host
=
mmc_priv
(
mmc
);
struct
variant_data
*
variant
=
host
->
variant
;
u32
pwr
=
0
;
unsigned
long
flags
;
int
ret
;
pm_runtime_get_sync
(
mmc_dev
(
mmc
));
if
(
host
->
plat
->
ios_handler
&&
host
->
plat
->
ios_handler
(
mmc_dev
(
mmc
),
ios
))
dev_err
(
mmc_dev
(
mmc
),
"platform ios_handler failed
\n
"
);
switch
(
ios
->
power_mode
)
{
case
MMC_POWER_OFF
:
if
(
host
->
vcc
)
...
...
@@ -1035,22 +1088,38 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
* power should be rare so we print an error
* and return here.
*/
return
;
goto
out
;
}
}
if
(
host
->
plat
->
vdd_handler
)
pwr
|=
host
->
plat
->
vdd_handler
(
mmc_dev
(
mmc
),
ios
->
vdd
,
ios
->
power_mode
);
/* The ST version does not have this, fall through to POWER_ON */
if
(
host
->
hw_designer
!=
AMBA_VENDOR_ST
)
{
pwr
|=
MCI_PWR_UP
;
break
;
}
/*
* The ST Micro variant doesn't have the PL180s MCI_PWR_UP
* and instead uses MCI_PWR_ON so apply whatever value is
* configured in the variant data.
*/
pwr
|=
variant
->
pwrreg_powerup
;
break
;
case
MMC_POWER_ON
:
pwr
|=
MCI_PWR_ON
;
break
;
}
if
(
variant
->
signal_direction
&&
ios
->
power_mode
!=
MMC_POWER_OFF
)
{
/*
* The ST Micro variant has some additional bits
* indicating signal direction for the signals in
* the SD/MMC bus and feedback-clock usage.
*/
pwr
|=
host
->
plat
->
sigdir
;
if
(
ios
->
bus_width
==
MMC_BUS_WIDTH_4
)
pwr
&=
~
MCI_ST_DATA74DIREN
;
else
if
(
ios
->
bus_width
==
MMC_BUS_WIDTH_1
)
pwr
&=
(
~
MCI_ST_DATA74DIREN
&
~
MCI_ST_DATA31DIREN
&
~
MCI_ST_DATA2DIREN
);
}
if
(
ios
->
bus_mode
==
MMC_BUSMODE_OPENDRAIN
)
{
if
(
host
->
hw_designer
!=
AMBA_VENDOR_ST
)
pwr
|=
MCI_ROD
;
...
...
@@ -1066,13 +1135,13 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
spin_lock_irqsave
(
&
host
->
lock
,
flags
);
mmci_set_clkreg
(
host
,
ios
->
clock
);
if
(
host
->
pwr
!=
pwr
)
{
host
->
pwr
=
pwr
;
writel
(
pwr
,
host
->
base
+
MMCIPOWER
);
}
mmci_write_pwrreg
(
host
,
pwr
);
spin_unlock_irqrestore
(
&
host
->
lock
,
flags
);
out:
pm_runtime_mark_last_busy
(
mmc_dev
(
mmc
));
pm_runtime_put_autosuspend
(
mmc_dev
(
mmc
));
}
static
int
mmci_get_ro
(
struct
mmc_host
*
mmc
)
...
...
@@ -1345,6 +1414,8 @@ static int __devinit mmci_probe(struct amba_device *dev,
mmci_dma_setup
(
host
);
pm_runtime_set_autosuspend_delay
(
&
dev
->
dev
,
50
);
pm_runtime_use_autosuspend
(
&
dev
->
dev
);
pm_runtime_put
(
&
dev
->
dev
);
mmc_add_host
(
mmc
);
...
...
@@ -1429,43 +1500,49 @@ static int __devexit mmci_remove(struct amba_device *dev)
return
0
;
}
#ifdef CONFIG_
PM
static
int
mmci_suspend
(
struct
amba_device
*
dev
,
pm_message_t
state
)
#ifdef CONFIG_
SUSPEND
static
int
mmci_suspend
(
struct
device
*
dev
)
{
struct
mmc_host
*
mmc
=
amba_get_drvdata
(
dev
);
struct
amba_device
*
adev
=
to_amba_device
(
dev
);
struct
mmc_host
*
mmc
=
amba_get_drvdata
(
adev
);
int
ret
=
0
;
if
(
mmc
)
{
struct
mmci_host
*
host
=
mmc_priv
(
mmc
);
ret
=
mmc_suspend_host
(
mmc
);
if
(
ret
==
0
)
if
(
ret
==
0
)
{
pm_runtime_get_sync
(
dev
);
writel
(
0
,
host
->
base
+
MMCIMASK0
);
}
}
return
ret
;
}
static
int
mmci_resume
(
struct
amba_
device
*
dev
)
static
int
mmci_resume
(
struct
device
*
dev
)
{
struct
mmc_host
*
mmc
=
amba_get_drvdata
(
dev
);
struct
amba_device
*
adev
=
to_amba_device
(
dev
);
struct
mmc_host
*
mmc
=
amba_get_drvdata
(
adev
);
int
ret
=
0
;
if
(
mmc
)
{
struct
mmci_host
*
host
=
mmc_priv
(
mmc
);
writel
(
MCI_IRQENABLE
,
host
->
base
+
MMCIMASK0
);
pm_runtime_put
(
dev
);
ret
=
mmc_resume_host
(
mmc
);
}
return
ret
;
}
#else
#define mmci_suspend NULL
#define mmci_resume NULL
#endif
static
const
struct
dev_pm_ops
mmci_dev_pm_ops
=
{
SET_SYSTEM_SLEEP_PM_OPS
(
mmci_suspend
,
mmci_resume
)
};
static
struct
amba_id
mmci_ids
[]
=
{
{
.
id
=
0x00041180
,
...
...
@@ -1511,11 +1588,10 @@ MODULE_DEVICE_TABLE(amba, mmci_ids);
static
struct
amba_driver
mmci_driver
=
{
.
drv
=
{
.
name
=
DRIVER_NAME
,
.
pm
=
&
mmci_dev_pm_ops
,
},
.
probe
=
mmci_probe
,
.
remove
=
__devexit_p
(
mmci_remove
),
.
suspend
=
mmci_suspend
,
.
resume
=
mmci_resume
,
.
id_table
=
mmci_ids
,
};
...
...
drivers/mmc/host/mmci.h
浏览文件 @
bba1594d
...
...
@@ -13,16 +13,6 @@
#define MCI_PWR_ON 0x03
#define MCI_OD (1 << 6)
#define MCI_ROD (1 << 7)
/*
* The ST Micro version does not have ROD and reuse the voltage registers
* for direction settings
*/
#define MCI_ST_DATA2DIREN (1 << 2)
#define MCI_ST_CMDDIREN (1 << 3)
#define MCI_ST_DATA0DIREN (1 << 4)
#define MCI_ST_DATA31DIREN (1 << 5)
#define MCI_ST_FBCLKEN (1 << 7)
#define MCI_ST_DATA74DIREN (1 << 8)
#define MMCICLOCK 0x004
#define MCI_CLK_ENABLE (1 << 8)
...
...
@@ -160,7 +150,7 @@
(MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \
MCI_TXFIFOHALFEMPTYMASK)
#define NR_SG 1
6
#define NR_SG 1
28
struct
clk
;
struct
variant_data
;
...
...
@@ -189,7 +179,8 @@ struct mmci_host {
unsigned
int
mclk
;
unsigned
int
cclk
;
u32
pwr
;
u32
pwr_reg
;
u32
clk_reg
;
struct
mmci_platform_data
*
plat
;
struct
variant_data
*
variant
;
...
...
include/linux/amba/mmci.h
浏览文件 @
bba1594d
...
...
@@ -6,6 +6,19 @@
#include <linux/mmc/host.h>
/*
* These defines is places here due to access is needed from machine
* configuration files. The ST Micro version does not have ROD and
* reuse the voltage registers for direction settings.
*/
#define MCI_ST_DATA2DIREN (1 << 2)
#define MCI_ST_CMDDIREN (1 << 3)
#define MCI_ST_DATA0DIREN (1 << 4)
#define MCI_ST_DATA31DIREN (1 << 5)
#define MCI_ST_FBCLKEN (1 << 7)
#define MCI_ST_DATA74DIREN (1 << 8)
/* Just some dummy forwarding */
struct
dma_chan
;
...
...
@@ -18,7 +31,8 @@ struct dma_chan;
* @ocr_mask: available voltages on the 4 pins from the block, this
* is ignored if a regulator is used, see the MMC_VDD_* masks in
* mmc/host.h
* @vdd_handler: a callback function to translate a MMC_VDD_*
* @ios_handler: a callback function to act on specfic ios changes,
* used for example to control a levelshifter
* mask into a value to be binary (or set some other custom bits
* in MMCIPWR) or:ed and written into the MMCIPWR register of the
* block. May also control external power based on the power_mode.
...
...
@@ -31,6 +45,8 @@ struct dma_chan;
* @capabilities: the capabilities of the block as implemented in
* this platform, signify anything MMC_CAP_* from mmc/host.h
* @capabilities2: more capabilities, MMC_CAP2_* from mmc/host.h
* @sigdir: a bit field indicating for what bits in the MMC bus the host
* should enable signal direction indication.
* @dma_filter: function used to select an appropriate RX and TX
* DMA channel to be used for DMA, if and only if you're deploying the
* generic DMA engine
...
...
@@ -46,14 +62,14 @@ struct dma_chan;
struct
mmci_platform_data
{
unsigned
int
f_max
;
unsigned
int
ocr_mask
;
u32
(
*
vdd_handler
)(
struct
device
*
,
unsigned
int
vdd
,
unsigned
char
power_mode
);
int
(
*
ios_handler
)(
struct
device
*
,
struct
mmc_ios
*
);
unsigned
int
(
*
status
)(
struct
device
*
);
int
gpio_wp
;
int
gpio_cd
;
bool
cd_invert
;
unsigned
long
capabilities
;
unsigned
long
capabilities2
;
u32
sigdir
;
bool
(
*
dma_filter
)(
struct
dma_chan
*
chan
,
void
*
filter_param
);
void
*
dma_rx_param
;
void
*
dma_tx_param
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录