Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
aa312be1
K
Kernel
项目概览
openeuler
/
Kernel
大约 1 年 前同步成功
通知
7
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看板
提交
aa312be1
编写于
1月 05, 2011
作者:
R
Russell King
浏览文件
操作
浏览文件
下载
差异文件
Merge branches 'mmci' and 'pl011-dma' into devel
上级
31edf274
8c11a94d
38d62436
变更
4
展开全部
隐藏空白更改
内联
并排
Showing
4 changed file
with
769 addition
and
61 deletion
+769
-61
drivers/mmc/host/mmci.c
drivers/mmc/host/mmci.c
+177
-30
drivers/mmc/host/mmci.h
drivers/mmc/host/mmci.h
+9
-0
drivers/serial/amba-pl011.c
drivers/serial/amba-pl011.c
+561
-31
include/linux/amba/serial.h
include/linux/amba/serial.h
+22
-0
未找到文件。
drivers/mmc/host/mmci.c
浏览文件 @
aa312be1
...
...
@@ -19,6 +19,7 @@
#include <linux/highmem.h>
#include <linux/log2.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/amba/bus.h>
#include <linux/clk.h>
#include <linux/scatterlist.h>
...
...
@@ -45,6 +46,12 @@ static unsigned int fmax = 515633;
* is asserted (likewise for RX)
* @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
* is asserted (likewise for RX)
* @broken_blockend: the MCI_DATABLOCKEND is broken on the hardware
* and will not work at all.
* @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when
* using DMA.
* @sdio: variant supports SDIO
* @st_clkdiv: true if using a ST-specific clock divider algorithm
*/
struct
variant_data
{
unsigned
int
clkreg
;
...
...
@@ -52,6 +59,10 @@ struct variant_data {
unsigned
int
datalength_bits
;
unsigned
int
fifosize
;
unsigned
int
fifohalfsize
;
bool
broken_blockend
;
bool
broken_blockend_dma
;
bool
sdio
;
bool
st_clkdiv
;
};
static
struct
variant_data
variant_arm
=
{
...
...
@@ -65,6 +76,8 @@ static struct variant_data variant_u300 = {
.
fifohalfsize
=
8
*
4
,
.
clkreg_enable
=
1
<<
13
,
/* HWFCEN */
.
datalength_bits
=
16
,
.
broken_blockend_dma
=
true
,
.
sdio
=
true
,
};
static
struct
variant_data
variant_ux500
=
{
...
...
@@ -73,7 +86,11 @@ static struct variant_data variant_ux500 = {
.
clkreg
=
MCI_CLK_ENABLE
,
.
clkreg_enable
=
1
<<
14
,
/* HWFCEN */
.
datalength_bits
=
24
,
.
broken_blockend
=
true
,
.
sdio
=
true
,
.
st_clkdiv
=
true
,
};
/*
* This must be called with host->lock held
*/
...
...
@@ -86,7 +103,22 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
if
(
desired
>=
host
->
mclk
)
{
clk
=
MCI_CLK_BYPASS
;
host
->
cclk
=
host
->
mclk
;
}
else
if
(
variant
->
st_clkdiv
)
{
/*
* DB8500 TRM says f = mclk / (clkdiv + 2)
* => clkdiv = (mclk / f) - 2
* Round the divider up so we don't exceed the max
* frequency
*/
clk
=
DIV_ROUND_UP
(
host
->
mclk
,
desired
)
-
2
;
if
(
clk
>=
256
)
clk
=
255
;
host
->
cclk
=
host
->
mclk
/
(
clk
+
2
);
}
else
{
/*
* PL180 TRM says f = mclk / (2 * (clkdiv + 1))
* => clkdiv = mclk / (2 * f) - 1
*/
clk
=
host
->
mclk
/
(
2
*
desired
)
-
1
;
if
(
clk
>=
256
)
clk
=
255
;
...
...
@@ -129,10 +161,26 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
spin_lock
(
&
host
->
lock
);
}
static
void
mmci_set_mask1
(
struct
mmci_host
*
host
,
unsigned
int
mask
)
{
void
__iomem
*
base
=
host
->
base
;
if
(
host
->
singleirq
)
{
unsigned
int
mask0
=
readl
(
base
+
MMCIMASK0
);
mask0
&=
~
MCI_IRQ1MASK
;
mask0
|=
mask
;
writel
(
mask0
,
base
+
MMCIMASK0
);
}
writel
(
mask
,
base
+
MMCIMASK1
);
}
static
void
mmci_stop_data
(
struct
mmci_host
*
host
)
{
writel
(
0
,
host
->
base
+
MMCIDATACTRL
);
writel
(
0
,
host
->
base
+
MMCIMASK1
);
mmci_set_mask1
(
host
,
0
);
host
->
data
=
NULL
;
}
...
...
@@ -162,6 +210,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
host
->
data
=
data
;
host
->
size
=
data
->
blksz
*
data
->
blocks
;
host
->
data_xfered
=
0
;
host
->
blockend
=
false
;
host
->
dataend
=
false
;
mmci_init_sg
(
host
,
data
);
...
...
@@ -196,9 +246,14 @@ 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
);
writel
(
irqmask
,
base
+
MMCIMASK1
);
mmci_set_mask1
(
host
,
irqmask
);
}
static
void
...
...
@@ -233,20 +288,9 @@ static void
mmci_data_irq
(
struct
mmci_host
*
host
,
struct
mmc_data
*
data
,
unsigned
int
status
)
{
if
(
status
&
MCI_DATABLOCKEND
)
{
host
->
data_xfered
+=
data
->
blksz
;
#ifdef CONFIG_ARCH_U300
/*
* On the U300 some signal or other is
* badly routed so that a data write does
* not properly terminate with a MCI_DATAEND
* status flag. This quirk will make writes
* work again.
*/
if
(
data
->
flags
&
MMC_DATA_WRITE
)
status
|=
MCI_DATAEND
;
#endif
}
struct
variant_data
*
variant
=
host
->
variant
;
/* First check for errors */
if
(
status
&
(
MCI_DATACRCFAIL
|
MCI_DATATIMEOUT
|
MCI_TXUNDERRUN
|
MCI_RXOVERRUN
))
{
dev_dbg
(
mmc_dev
(
host
->
mmc
),
"MCI ERROR IRQ (status %08x)
\n
"
,
status
);
if
(
status
&
MCI_DATACRCFAIL
)
...
...
@@ -255,7 +299,10 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
data
->
error
=
-
ETIMEDOUT
;
else
if
(
status
&
(
MCI_TXUNDERRUN
|
MCI_RXOVERRUN
))
data
->
error
=
-
EIO
;
status
|=
MCI_DATAEND
;
/* Force-complete the transaction */
host
->
blockend
=
true
;
host
->
dataend
=
true
;
/*
* We hit an error condition. Ensure that any data
...
...
@@ -273,9 +320,64 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
local_irq_restore
(
flags
);
}
}
if
(
status
&
MCI_DATAEND
)
{
/*
* On ARM variants in PIO mode, MCI_DATABLOCKEND
* is always sent first, and we increase the
* transfered number of bytes for that IRQ. Then
* MCI_DATAEND follows and we conclude the transaction.
*
* On the Ux500 single-IRQ variant MCI_DATABLOCKEND
* doesn't seem to immediately clear from the status,
* so we can't use it keep count when only one irq is
* used because the irq will hit for other reasons, and
* then the flag is still up. So we use the MCI_DATAEND
* IRQ at the end of the entire transfer because
* MCI_DATABLOCKEND is broken.
*
* In the U300, the IRQs can arrive out-of-order,
* e.g. MCI_DATABLOCKEND sometimes arrives after MCI_DATAEND,
* so for this case we use the flags "blockend" and
* "dataend" to make sure both IRQs have arrived before
* concluding the transaction. (This does not apply
* to the Ux500 which doesn't fire MCI_DATABLOCKEND
* at all.) In DMA mode it suffers from the same problem
* as the Ux500.
*/
if
(
status
&
MCI_DATABLOCKEND
)
{
/*
* Just being a little over-cautious, we do not
* use this progressive update if the hardware blockend
* flag is unreliable: since it can stay high between
* IRQs it will corrupt the transfer counter.
*/
if
(
!
variant
->
broken_blockend
)
host
->
data_xfered
+=
data
->
blksz
;
host
->
blockend
=
true
;
}
if
(
status
&
MCI_DATAEND
)
host
->
dataend
=
true
;
/*
* On variants with broken blockend we shall only wait for dataend,
* on others we must sync with the blockend signal since they can
* appear out-of-order.
*/
if
(
host
->
dataend
&&
(
host
->
blockend
||
variant
->
broken_blockend
))
{
mmci_stop_data
(
host
);
/* Reset these flags */
host
->
blockend
=
false
;
host
->
dataend
=
false
;
/*
* Variants with broken blockend flags need to handle the
* end of the entire transfer here.
*/
if
(
variant
->
broken_blockend
&&
!
data
->
error
)
host
->
data_xfered
+=
data
->
blksz
*
data
->
blocks
;
if
(
!
data
->
stop
)
{
mmci_request_end
(
host
,
data
->
mrq
);
}
else
{
...
...
@@ -356,7 +458,32 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem
variant
->
fifosize
:
variant
->
fifohalfsize
;
count
=
min
(
remain
,
maxcnt
);
writesl
(
base
+
MMCIFIFO
,
ptr
,
count
>>
2
);
/*
* The ST Micro variant for SDIO transfer sizes
* less then 8 bytes should have clock H/W flow
* control disabled.
*/
if
(
variant
->
sdio
&&
mmc_card_sdio
(
host
->
mmc
->
card
))
{
if
(
count
<
8
)
writel
(
readl
(
host
->
base
+
MMCICLOCK
)
&
~
variant
->
clkreg_enable
,
host
->
base
+
MMCICLOCK
);
else
writel
(
readl
(
host
->
base
+
MMCICLOCK
)
|
variant
->
clkreg_enable
,
host
->
base
+
MMCICLOCK
);
}
/*
* SDIO especially may want to send something that is
* not divisible by 4 (as opposed to card sectors
* etc), and the FIFO only accept full 32-bit writes.
* So compensate by adding +3 on the count, a single
* byte become a 32bit write, 7 bytes will be two
* 32bit writes etc.
*/
writesl
(
base
+
MMCIFIFO
,
ptr
,
(
count
+
3
)
>>
2
);
ptr
+=
count
;
remain
-=
count
;
...
...
@@ -437,7 +564,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
* "any data available" mode.
*/
if
(
status
&
MCI_RXACTIVE
&&
host
->
size
<
variant
->
fifosize
)
writel
(
MCI_RXDATAAVLBLMASK
,
base
+
MMCIMASK1
);
mmci_set_mask1
(
host
,
MCI_RXDATAAVLBLMASK
);
/*
* If we run out of data, disable the data IRQs; this
...
...
@@ -446,7 +573,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
* stops us racing with our data end IRQ.
*/
if
(
host
->
size
==
0
)
{
writel
(
0
,
base
+
MMCIMASK1
);
mmci_set_mask1
(
host
,
0
);
writel
(
readl
(
base
+
MMCIMASK0
)
|
MCI_DATAENDMASK
,
base
+
MMCIMASK0
);
}
...
...
@@ -469,6 +596,14 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
struct
mmc_data
*
data
;
status
=
readl
(
host
->
base
+
MMCISTATUS
);
if
(
host
->
singleirq
)
{
if
(
status
&
readl
(
host
->
base
+
MMCIMASK1
))
mmci_pio_irq
(
irq
,
dev_id
);
status
&=
~
MCI_IRQ1MASK
;
}
status
&=
readl
(
host
->
base
+
MMCIMASK0
);
writel
(
status
,
host
->
base
+
MMCICLEAR
);
...
...
@@ -635,6 +770,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
struct
variant_data
*
variant
=
id
->
data
;
struct
mmci_host
*
host
;
struct
mmc_host
*
mmc
;
unsigned
int
mask
;
int
ret
;
/* must have platform data */
...
...
@@ -806,20 +942,30 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
if
(
ret
)
goto
unmap
;
ret
=
request_irq
(
dev
->
irq
[
1
],
mmci_pio_irq
,
IRQF_SHARED
,
DRIVER_NAME
" (pio)"
,
host
);
if
(
ret
)
goto
irq0_free
;
if
(
dev
->
irq
[
1
]
==
NO_IRQ
)
host
->
singleirq
=
true
;
else
{
ret
=
request_irq
(
dev
->
irq
[
1
],
mmci_pio_irq
,
IRQF_SHARED
,
DRIVER_NAME
" (pio)"
,
host
);
if
(
ret
)
goto
irq0_free
;
}
writel
(
MCI_IRQENABLE
,
host
->
base
+
MMCIMASK0
);
mask
=
MCI_IRQENABLE
;
/* Don't use the datablockend flag if it's broken */
if
(
variant
->
broken_blockend
)
mask
&=
~
MCI_DATABLOCKEND
;
amba_set_drvdata
(
dev
,
mmc
);
writel
(
mask
,
host
->
base
+
MMCIMASK0
);
mmc_add_host
(
mmc
);
amba_set_drvdata
(
dev
,
mmc
);
dev_info
(
&
dev
->
dev
,
"%s:
MMCI rev %x cfg %02x at 0x%016
llx irq %d,%d
\n
"
,
mmc_hostname
(
mmc
),
amba_
rev
(
dev
),
amba_config
(
dev
),
dev_info
(
&
dev
->
dev
,
"%s:
PL%03x rev%u at 0x%08
llx irq %d,%d
\n
"
,
mmc_hostname
(
mmc
),
amba_
part
(
dev
),
amba_rev
(
dev
),
(
unsigned
long
long
)
dev
->
res
.
start
,
dev
->
irq
[
0
],
dev
->
irq
[
1
]);
mmc_add_host
(
mmc
);
return
0
;
irq0_free:
...
...
@@ -864,7 +1010,8 @@ static int __devexit mmci_remove(struct amba_device *dev)
writel
(
0
,
host
->
base
+
MMCIDATACTRL
);
free_irq
(
dev
->
irq
[
0
],
host
);
free_irq
(
dev
->
irq
[
1
],
host
);
if
(
!
host
->
singleirq
)
free_irq
(
dev
->
irq
[
1
],
host
);
if
(
host
->
gpio_wp
!=
-
ENOSYS
)
gpio_free
(
host
->
gpio_wp
);
...
...
drivers/mmc/host/mmci.h
浏览文件 @
aa312be1
...
...
@@ -139,6 +139,11 @@
MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \
MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK)
/* These interrupts are directed to IRQ1 when two IRQ lines are available */
#define MCI_IRQ1MASK \
(MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \
MCI_TXFIFOHALFEMPTYMASK)
#define NR_SG 16
struct
clk
;
...
...
@@ -154,6 +159,7 @@ struct mmci_host {
int
gpio_cd
;
int
gpio_wp
;
int
gpio_cd_irq
;
bool
singleirq
;
unsigned
int
data_xfered
;
...
...
@@ -171,6 +177,9 @@ struct mmci_host {
struct
timer_list
timer
;
unsigned
int
oldstat
;
bool
blockend
;
bool
dataend
;
/* pio stuff */
struct
sg_mapping_iter
sg_miter
;
unsigned
int
size
;
...
...
drivers/serial/amba-pl011.c
浏览文件 @
aa312be1
此差异已折叠。
点击以展开。
include/linux/amba/serial.h
浏览文件 @
aa312be1
...
...
@@ -113,6 +113,21 @@
#define UART01x_LCRH_PEN 0x02
#define UART01x_LCRH_BRK 0x01
#define ST_UART011_DMAWM_RX_1 (0 << 3)
#define ST_UART011_DMAWM_RX_2 (1 << 3)
#define ST_UART011_DMAWM_RX_4 (2 << 3)
#define ST_UART011_DMAWM_RX_8 (3 << 3)
#define ST_UART011_DMAWM_RX_16 (4 << 3)
#define ST_UART011_DMAWM_RX_32 (5 << 3)
#define ST_UART011_DMAWM_RX_48 (6 << 3)
#define ST_UART011_DMAWM_TX_1 0
#define ST_UART011_DMAWM_TX_2 1
#define ST_UART011_DMAWM_TX_4 2
#define ST_UART011_DMAWM_TX_8 3
#define ST_UART011_DMAWM_TX_16 4
#define ST_UART011_DMAWM_TX_32 5
#define ST_UART011_DMAWM_TX_48 6
#define UART010_IIR_RTIS 0x08
#define UART010_IIR_TIS 0x04
#define UART010_IIR_RIS 0x02
...
...
@@ -180,6 +195,13 @@ struct amba_device; /* in uncompress this is included but amba/bus.h is not */
struct
amba_pl010_data
{
void
(
*
set_mctrl
)(
struct
amba_device
*
dev
,
void
__iomem
*
base
,
unsigned
int
mctrl
);
};
struct
dma_chan
;
struct
amba_pl011_data
{
bool
(
*
dma_filter
)(
struct
dma_chan
*
chan
,
void
*
filter_param
);
void
*
dma_rx_param
;
void
*
dma_tx_param
;
};
#endif
#endif
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录