Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
S
Simple PCIe FMC carrier SPEC
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
50
Issues
50
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
Simple PCIe FMC carrier SPEC
Commits
3e7a6262
Commit
3e7a6262
authored
Sep 02, 2019
by
Federico Vaga
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature/spiflash' into develop
parents
02eb8c61
94d7d1c2
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
364 additions
and
166 deletions
+364
-166
gn412x-fcl.c
software/kernel/gn412x-fcl.c
+136
-15
spec-core-fpga.c
software/kernel/spec-core-fpga.c
+5
-3
spi-ocores.c
software/kernel/spi-ocores.c
+223
-148
No files found.
software/kernel/gn412x-fcl.c
View file @
3e7a6262
...
...
@@ -13,6 +13,33 @@
#include "spec-compat.h"
#include "gn412x.h"
#define FCL_CTRL_START_FSM BIT(0)
#define FCL_CTRL_SPRI_EN BIT(1)
#define FCL_CTRL_FSM_EN BIT(2)
#define FCL_CTRL_SEND_CFG_DATA BIT(3)
#define FCL_CTRL_LAST_BYTE_CNT_1 (0x3 << 4)
#define FCL_CTRL_LAST_BYTE_CNT_2 (0x2 << 4)
#define FCL_CTRL_LAST_BYTE_CNT_3 (0x1 << 4)
#define FCL_CTRL_LAST_BYTE_CNT_4 (0x0 << 4)
#define FCL_CTRL_RESET BIT(6)
#define FCL_CTRL_DATA_PUSH_COMP BIT(7)
#define FCL_CTRL_SPRI_CLK_STOP_EN BIT(8)
#define FCL_SPRI_CLKOUT BIT(0)
#define FCL_SPRI_DATAOUT BIT(1)
#define FCL_SPRI_CONFIG BIT(2)
#define FCL_SPRI_DONE BIT(3)
#define FCL_SPRI_XI_SWAP BIT(4)
#define FCL_SPRI_STATUS BIT(5)
#define FCL_IRQ_SPRI_STATUS BIT(0)
#define FCL_IRQ_TIMER BIT(1)
#define FCL_IRQ_CONFIG_ERROR BIT(2)
#define FCL_IRQ_CONFIG_DONE BIT(3)
#define FCL_IRQ_FIFO_UNDRFL BIT(4)
#define FCL_IRQ_FIFO_HALFFULL BIT(5)
/* Compatibility layer */
static
int
gn412x_fcl_write_init
(
struct
fpga_manager
*
mgr
,
struct
fpga_image_info
*
info
,
...
...
@@ -122,8 +149,75 @@ struct gn412x_fcl_dev {
void
__iomem
*
mem
;
struct
fpga_manager
*
mgr
;
struct
dentry
*
dbg_dir
;
#define GN412X_DBG_REG_NAME "regs"
struct
dentry
*
dbg_reg
;
struct
debugfs_regset32
dbg_reg32
;
};
#define REG32(_name, _offset) {.name = _name, .offset = _offset}
static
const
struct
debugfs_reg32
gn412x_debugfs_reg32
[]
=
{
REG32
(
"FCL_CTRL"
,
FCL_CTRL
),
REG32
(
"FCL_STATUS"
,
FCL_STATUS
),
REG32
(
"FCL_IODATA_IN"
,
FCL_IODATA_IN
),
REG32
(
"FCL_IODATA_OUT"
,
FCL_IODATA_OUT
),
REG32
(
"FCL_EN"
,
FCL_EN
),
REG32
(
"FCL_TIMER0"
,
FCL_TIMER_0
),
REG32
(
"FCL_TIMER1"
,
FCL_TIMER_1
),
REG32
(
"FCL_CLK_DIV"
,
FCL_CLK_DIV
),
REG32
(
"FCL_IRQ"
,
FCL_IRQ
),
REG32
(
"FCL_TIMER_CTRL"
,
FCL_TIMER_CTRL
),
REG32
(
"FCL_IM"
,
FCL_IM
),
REG32
(
"FCL_TIMER2_0"
,
FCL_TIMER2_0
),
REG32
(
"FCL_TIMER2_1"
,
FCL_TIMER2_1
),
REG32
(
"FCL_DBG_STS"
,
FCL_DBG_STS
),
};
static
int
gn4124_dbg_init
(
struct
platform_device
*
pdev
)
{
struct
gn412x_fcl_dev
*
gn412x
=
platform_get_drvdata
(
pdev
);
struct
dentry
*
dir
,
*
file
;
int
err
;
dir
=
debugfs_create_dir
(
dev_name
(
&
pdev
->
dev
),
NULL
);
if
(
IS_ERR_OR_NULL
(
dir
))
{
err
=
PTR_ERR
(
dir
);
dev_warn
(
&
pdev
->
dev
,
"Cannot create debugfs directory
\"
%s
\"
(%d)
\n
"
,
dev_name
(
&
pdev
->
dev
),
err
);
goto
err_dir
;
}
gn412x
->
dbg_reg32
.
regs
=
gn412x_debugfs_reg32
;
gn412x
->
dbg_reg32
.
nregs
=
ARRAY_SIZE
(
gn412x_debugfs_reg32
);
gn412x
->
dbg_reg32
.
base
=
gn412x
->
mem
;
file
=
debugfs_create_regset32
(
GN412X_DBG_REG_NAME
,
0200
,
dir
,
&
gn412x
->
dbg_reg32
);
if
(
IS_ERR_OR_NULL
(
file
))
{
err
=
PTR_ERR
(
file
);
dev_warn
(
&
pdev
->
dev
,
"Cannot create debugfs file
\"
%s
\"
(%d)
\n
"
,
GN412X_DBG_REG_NAME
,
err
);
goto
err_reg32
;
}
gn412x
->
dbg_dir
=
dir
;
gn412x
->
dbg_reg
=
file
;
return
0
;
err_reg32:
debugfs_remove_recursive
(
dir
);
err_dir:
return
err
;
}
static
void
gn4124_dbg_exit
(
struct
platform_device
*
pdev
)
{
struct
gn412x_fcl_dev
*
gn412x
=
platform_get_drvdata
(
pdev
);
debugfs_remove_recursive
(
gn412x
->
dbg_dir
);
}
static
uint32_t
gn412x_ioread32
(
struct
gn412x_fcl_dev
*
gn412x
,
int
reg
)
{
...
...
@@ -182,7 +276,6 @@ static void gn4124_fpga_reset(struct gn412x_fcl_dev *gn412x)
GNPCI_SYS_CFG_SYSTEM
);
}
/**
* Initialize the gennum
* @gn412x: gn412x device instance
...
...
@@ -193,31 +286,35 @@ static void gn4124_fpga_reset(struct gn412x_fcl_dev *gn412x)
static
int
gn4124_fpga_fcl_init
(
struct
gn412x_fcl_dev
*
gn412x
,
int
last_word_size
)
{
uint32_t
ctrl
;
uint32_t
ctrl
,
en
;
int
i
;
gn412x_iowrite32
(
gn412x
,
0x00
,
FCL_CLK_DIV
);
gn412x_iowrite32
(
gn412x
,
0x40
,
FCL_CTRL
);
/* Reset */
gn412x_iowrite32
(
gn412x
,
FCL_CTRL_RESET
,
FCL_CTRL
);
i
=
gn412x_ioread32
(
gn412x
,
FCL_CTRL
);
if
(
i
!=
0x40
)
{
if
(
i
!=
FCL_CTRL_RESET
)
{
pr_err
(
"%s: %i: error
\n
"
,
__func__
,
__LINE__
);
return
-
EIO
;
}
gn412x_iowrite32
(
gn412x
,
0x00
,
FCL_CTRL
);
gn412x_iowrite32
(
gn412x
,
0x00
,
FCL_IRQ
);
/* clear pending irq */
ctrl
=
0
;
ctrl
|=
FCL_CTRL_SPRI_EN
;
ctrl
|=
FCL_CTRL_FSM_EN
;
ctrl
|=
FCL_CTRL_SPRI_CLK_STOP_EN
;
switch
(
last_word_size
)
{
case
3
:
ctrl
=
0x116
;
ctrl
|=
FCL_CTRL_LAST_BYTE_CNT_3
;
break
;
case
2
:
ctrl
=
0x126
;
ctrl
|=
FCL_CTRL_LAST_BYTE_CNT_2
;
break
;
case
1
:
ctrl
=
0x136
;
ctrl
|=
FCL_CTRL_LAST_BYTE_CNT_1
;
break
;
case
0
:
ctrl
=
0x106
;
ctrl
|=
FCL_CTRL_LAST_BYTE_CNT_4
;
break
;
default:
return
-
EINVAL
;
}
...
...
@@ -233,9 +330,14 @@ static int gn4124_fpga_fcl_init(struct gn412x_fcl_dev *gn412x,
*/
gn412x_iowrite32
(
gn412x
,
0x08
,
FCL_TIMER2_0
);
gn412x_iowrite32
(
gn412x
,
0x00
,
FCL_TIMER2_1
);
gn412x_iowrite32
(
gn412x
,
0x17
,
FCL_EN
);
ctrl
|=
0x01
;
/* "start FSM configuration" */
en
=
0
;
en
|=
FCL_SPRI_CLKOUT
;
en
|=
FCL_SPRI_DATAOUT
;
en
|=
FCL_SPRI_CONFIG
;
en
|=
FCL_SPRI_XI_SWAP
;
gn412x_iowrite32
(
gn412x
,
en
,
FCL_EN
);
ctrl
|=
FCL_CTRL_START_FSM
;
gn412x_iowrite32
(
gn412x
,
ctrl
,
FCL_CTRL
);
return
0
;
...
...
@@ -292,12 +394,12 @@ static int gn4124_fpga_load(struct gn412x_fcl_dev *gn412x,
/* Check to see if FPGA configuation has error */
int
i
=
gn412x_ioread32
(
gn412x
,
FCL_IRQ
);
if
((
i
&
8
)
&&
wrote
)
{
if
((
i
&
FCL_IRQ_CONFIG_DONE
)
&&
wrote
)
{
done
=
1
;
pr_err
(
"%s: %i: done after %i%i
\n
"
,
__func__
,
__LINE__
,
wrote
,
((
len
+
3
)
>>
2
));
}
else
if
((
i
&
0x4
)
&&
!
done
)
{
}
else
if
((
i
&
FCL_IRQ_CONFIG_ERROR
)
&&
!
done
)
{
pr_err
(
"%s: %i: error after %i/%i
\n
"
,
__func__
,
__LINE__
,
wrote
,
((
len
+
3
)
>>
2
));
...
...
@@ -305,7 +407,7 @@ static int gn4124_fpga_load(struct gn412x_fcl_dev *gn412x,
}
/* Wait until at least 1/2 of the fifo is empty */
while
(
gn412x_ioread32
(
gn412x
,
FCL_IRQ
)
&
(
1
<<
5
)
)
while
(
gn412x_ioread32
(
gn412x
,
FCL_IRQ
)
&
FCL_IRQ_FIFO_HALFFULL
)
;
/* Write a few dwords into FIFO at a time. */
...
...
@@ -326,7 +428,13 @@ static int gn4124_fpga_load(struct gn412x_fcl_dev *gn412x,
*/
static
void
gn4124_fpga_fcl_complete
(
struct
gn412x_fcl_dev
*
gn412x
)
{
gn412x_iowrite32
(
gn412x
,
0x186
,
FCL_CTRL
);
/* "last data written" */
uint32_t
ctrl
=
0
;
ctrl
|=
FCL_CTRL_SPRI_EN
;
ctrl
|=
FCL_CTRL_FSM_EN
;
ctrl
|=
FCL_CTRL_DATA_PUSH_COMP
;
ctrl
|=
FCL_CTRL_SPRI_CLK_STOP_EN
;
gn412x_iowrite32
(
gn412x
,
ctrl
,
FCL_CTRL
);
}
...
...
@@ -363,6 +471,12 @@ static int gn412x_fcl_write(struct fpga_manager *mgr,
}
static
void
gn4124_fcl_reset
(
struct
gn412x_fcl_dev
*
gn412x
)
{
gn412x_iowrite32
(
gn412x
,
0x00
,
FCL_CTRL
);
gn412x_iowrite32
(
gn412x
,
0x00
,
FCL_EN
);
}
static
int
gn412x_fcl_write_complete
(
struct
fpga_manager
*
mgr
,
struct
fpga_image_info
*
info
)
{
...
...
@@ -375,6 +489,7 @@ static int gn412x_fcl_write_complete(struct fpga_manager *mgr,
if
(
err
<
0
)
return
err
;
gn4124_fcl_reset
(
gn412x
);
gn4124_fpga_reset
(
gn412x
);
return
0
;
...
...
@@ -421,6 +536,9 @@ static int gn412x_fcl_probe(struct platform_device *pdev)
goto
err_map
;
}
gn4124_fcl_reset
(
gn412x
);
gn4124_dbg_init
(
pdev
);
gn412x
->
mgr
=
compat_fpga_mgr_create
(
&
pdev
->
dev
,
dev_name
(
&
pdev
->
dev
),
...
...
@@ -439,6 +557,7 @@ static int gn412x_fcl_probe(struct platform_device *pdev)
err_fpga_reg:
compat_fpga_mgr_free
(
gn412x
->
mgr
);
err_fpga_create:
gn4124_dbg_exit
(
pdev
);
devm_iounmap
(
&
pdev
->
dev
,
gn412x
->
mem
);
err_map:
err_res_mem:
...
...
@@ -450,6 +569,8 @@ static int gn412x_fcl_remove(struct platform_device *pdev)
{
struct
gn412x_fcl_dev
*
gn412x
=
platform_get_drvdata
(
pdev
);
gn4124_dbg_exit
(
pdev
);
if
(
!
gn412x
->
mgr
)
return
-
ENODEV
;
...
...
software/kernel/spec-core-fpga.c
View file @
3e7a6262
...
...
@@ -323,10 +323,12 @@ static struct resource spec_fpga_fmc_i2c_res[] = {
},
};
#define SPEC_FPGA_WB_CLK_HZ 62500000
#define SPEC_FPGA_WB_CLK_KHZ (SPEC_FPGA_WB_CLK_HZ / 1000)
static
struct
ocores_i2c_platform_data
spec_fpga_fmc_i2c_pdata
=
{
.
reg_shift
=
2
,
/* 32bit aligned */
.
reg_io_width
=
4
,
.
clock_khz
=
62500
,
.
clock_khz
=
SPEC_FPGA_WB_CLK_KHZ
,
.
big_endian
=
0
,
.
num_devices
=
0
,
.
devices
=
NULL
,
...
...
@@ -356,7 +358,7 @@ struct flash_platform_data spec_flash_pdata = {
static
struct
spi_board_info
spec_fpga_spi_devices_info
[]
=
{
{
.
modalias
=
"m25p32"
,
.
max_speed_hz
=
75000000
,
.
max_speed_hz
=
SPEC_FPGA_WB_CLK_HZ
/
128
,
.
chip_select
=
0
,
.
platform_data
=
&
spec_flash_pdata
,
}
...
...
@@ -364,7 +366,7 @@ static struct spi_board_info spec_fpga_spi_devices_info[] = {
static
struct
spi_ocores_platform_data
spec_fpga_spi_pdata
=
{
.
big_endian
=
0
,
.
clock_hz
=
65200000
,
.
clock_hz
=
SPEC_FPGA_WB_CLK_HZ
,
.
num_devices
=
ARRAY_SIZE
(
spec_fpga_spi_devices_info
),
.
devices
=
spec_fpga_spi_devices_info
,
};
...
...
software/kernel/spi-ocores.c
View file @
3e7a6262
...
...
@@ -48,16 +48,15 @@ struct spi_ocores {
/* Current transfer */
struct
spi_transfer
*
cur_xfer
;
uint32_t
cur_ctrl
;
uint32_t
cur_divider
;
const
void
*
cur_tx_buf
;
unsigned
int
cur_tx_len
;
void
*
cur_rx_buf
;
unsigned
int
cur_rx_len
;
unsigned
int
cur_len
;
size_t
(
*
cur_tx_push
)(
struct
spi_ocores
*
sp
);
size_t
(
*
cur_rx_pop
)(
struct
spi_ocores
*
sp
);
/* Register Access functions */
uint32_t
(
*
read
)(
struct
spi_ocores
*
sp
,
unsigned
int
reg
);
void
(
*
write
)(
struct
spi_ocores
*
sp
,
u
nsigned
int
reg
,
uint32_t
val
);
void
(
*
write
)(
struct
spi_ocores
*
sp
,
u
int32_t
val
,
unsigned
int
reg
);
};
enum
spi_ocores_type
{
...
...
@@ -71,7 +70,7 @@ static inline uint32_t spi_ocores_ioread32(struct spi_ocores *sp,
}
static
inline
void
spi_ocores_iowrite32
(
struct
spi_ocores
*
sp
,
unsigned
int
reg
,
uint32_t
val
)
uint32_t
val
,
unsigned
int
reg
)
{
iowrite32
(
val
,
sp
->
mem
+
reg
);
}
...
...
@@ -83,7 +82,7 @@ static inline uint32_t spi_ocores_ioread32be(struct spi_ocores *sp,
}
static
inline
void
spi_ocores_iowrite32be
(
struct
spi_ocores
*
sp
,
u
nsigned
int
reg
,
uint32_t
val
)
u
int32_t
val
,
unsigned
int
reg
)
{
iowrite32be
(
val
,
sp
->
mem
+
reg
);
}
...
...
@@ -167,11 +166,15 @@ static void spi_ocores_tx_set(struct spi_ocores *sp,
*/
static
uint32_t
spi_ocores_rx_get
(
struct
spi_ocores
*
sp
,
unsigned
int
idx
)
{
uint32_t
val
;
if
(
WARN
(
idx
>
3
,
"Invalid RX register index %d (min:0, max: 3)
\n
"
,
idx
))
return
0
;
return
sp
->
read
(
sp
,
SPI_OCORES_RX
(
idx
));
val
=
sp
->
read
(
sp
,
SPI_OCORES_RX
(
idx
));
return
val
;
}
/**
...
...
@@ -191,172 +194,158 @@ static uint8_t spi_ocores_hw_xfer_bits_per_word(struct spi_ocores *sp)
return
nbits
;
}
static
void
spi_ocores_hw_xfer_tx_push8
(
struct
spi_ocores
*
sp
)
static
size_t
spi_ocores_hw_xfer_tx_push8
(
struct
spi_ocores
*
sp
)
{
uint
32
_t
data
;
uint
8
_t
data
;
data
=
*
((
uint8_t
*
)
sp
->
cur_tx_buf
);
sp
->
cur_tx_buf
+=
1
;
data
=
((
uint8_t
*
)
sp
->
cur_tx_buf
)[
0
];
spi_ocores_tx_set
(
sp
,
0
,
data
);
sp
->
cur_tx_len
-=
1
;
return
sizeof
(
data
);
}
static
void
spi_ocores_hw_xfer_tx_push16
(
struct
spi_ocores
*
sp
)
static
size_t
spi_ocores_hw_xfer_tx_push16
(
struct
spi_ocores
*
sp
)
{
uint
32
_t
data
;
uint
16
_t
data
;
data
=
*
((
uint16_t
*
)
sp
->
cur_tx_buf
)
;
sp
->
cur_tx_buf
+=
2
;
spi_ocores_tx_set
(
sp
,
0
,
data
);
sp
->
cur_tx_len
-=
2
;
data
=
((
uint16_t
*
)
sp
->
cur_tx_buf
)[
0
]
;
sp
i_ocores_tx_set
(
sp
,
0
,
__cpu_to_be16
(
data
))
;
return
sizeof
(
data
)
;
}
static
void
spi_ocores_hw_xfer_tx_push32
(
struct
spi_ocores
*
sp
)
static
size_t
spi_ocores_hw_xfer_tx_push32
(
struct
spi_ocores
*
sp
)
{
uint32_t
data
;
data
=
*
((
uint32_t
*
)
sp
->
cur_tx_buf
)
;
sp
->
cur_tx_buf
+=
4
;
spi_ocores_tx_set
(
sp
,
0
,
data
);
sp
->
cur_tx_len
-=
4
;
data
=
((
uint32_t
*
)
sp
->
cur_tx_buf
)[
0
]
;
sp
i_ocores_tx_set
(
sp
,
0
,
__cpu_to_be32
(
data
))
;
return
sizeof
(
data
)
;
}
static
void
spi_ocores_hw_xfer_tx_push64
(
struct
spi_ocores
*
sp
)
static
size_t
spi_ocores_hw_xfer_tx_push64
(
struct
spi_ocores
*
sp
)
{
int
i
;
uint64_t
data
;
for
(
i
=
0
;
i
<
2
;
++
i
)
{
uint32_t
data
;
data
=
__cpu_to_be64
(
*
((
uint64_t
*
)
sp
->
cur_tx_buf
));
spi_ocores_tx_set
(
sp
,
0
,
data
&
0xFFFFFFFF
);
data
>>=
32
;
spi_ocores_tx_set
(
sp
,
1
,
data
&
0xFFFFFFFF
);
data
=
*
((
uint32_t
*
)
sp
->
cur_tx_buf
);
sp
->
cur_tx_buf
+=
4
;
spi_ocores_tx_set
(
sp
,
i
,
data
);
sp
->
cur_tx_len
-=
4
;
}
return
sizeof
(
data
);
}
static
void
spi_ocores_hw_xfer_tx_push128
(
struct
spi_ocores
*
sp
)
static
size_t
spi_ocores_hw_xfer_tx_push128
(
struct
spi_ocores
*
sp
)
{
int
i
;
uint64_t
data
;
for
(
i
=
0
;
i
<
4
;
++
i
)
{
uint32_t
data
;
data
=
__cpu_to_be64
(((
uint64_t
*
)
sp
->
cur_tx_buf
)[
0
]);
spi_ocores_tx_set
(
sp
,
2
,
data
&
0xFFFFFFFF
);
data
>>=
32
;
spi_ocores_tx_set
(
sp
,
3
,
data
&
0xFFFFFFFF
);
data
=
*
((
uint32_t
*
)
sp
->
cur_tx_buf
);
sp
->
cur_tx_buf
+=
4
;
spi_ocores_tx_set
(
sp
,
i
,
data
);
sp
->
cur_tx_len
-=
4
;
}
data
=
__cpu_to_be64
(((
uint64_t
*
)
sp
->
cur_tx_buf
)[
1
]);
spi_ocores_tx_set
(
sp
,
0
,
data
&
0xFFFFFFFF
);
data
>>=
32
;
spi_ocores_tx_set
(
sp
,
1
,
data
&
0xFFFFFFFF
);
return
sizeof
(
data
)
*
2
;
}
static
void
spi_ocores_hw_xfer_rx_push8
(
struct
spi_ocores
*
sp
)
static
size_t
spi_ocores_hw_xfer_tx_push
(
struct
spi_ocores
*
sp
)
{
uint32_t
data
;
size_t
len
=
0
;
if
(
sp
->
cur_tx_buf
)
len
=
sp
->
cur_tx_push
(
sp
);
sp
->
cur_tx_buf
+=
len
;
return
len
;
}
static
size_t
spi_ocores_hw_xfer_rx_pop8
(
struct
spi_ocores
*
sp
)
{
uint8_t
data
;
data
=
spi_ocores_rx_get
(
sp
,
0
)
&
0x000000FF
;
*
((
uint8_t
*
)
sp
->
cur_rx_buf
)
=
data
;
sp
->
cur_rx_buf
+=
1
;
sp
->
cur_rx_len
-=
1
;
((
uint8_t
*
)
sp
->
cur_rx_buf
)[
0
]
=
data
;
return
sizeof
(
data
)
;
}
static
void
spi_ocores_hw_xfer_rx_push
16
(
struct
spi_ocores
*
sp
)
static
size_t
spi_ocores_hw_xfer_rx_pop
16
(
struct
spi_ocores
*
sp
)
{
uint
32
_t
data
;
uint
16
_t
data
;
data
=
spi_ocores_rx_get
(
sp
,
0
)
&
0x0000FFFF
;
*
((
uint16_t
*
)
sp
->
cur_rx_buf
)
=
data
;
sp
->
cur_rx_buf
+=
2
;
sp
->
cur_rx_len
-=
2
;
((
uint16_t
*
)
sp
->
cur_rx_buf
)[
0
]
=
__be16_to_cpu
(
data
)
;
return
sizeof
(
data
)
;
}
static
void
spi_ocores_hw_xfer_rx_push
32
(
struct
spi_ocores
*
sp
)
static
size_t
spi_ocores_hw_xfer_rx_pop
32
(
struct
spi_ocores
*
sp
)
{
uint32_t
data
;
data
=
spi_ocores_rx_get
(
sp
,
0
)
&
0xFFFFFFFF
;
*
((
uint32_t
*
)
sp
->
cur_rx_buf
)
=
data
;
sp
->
cur_rx_buf
+=
4
;
sp
->
cur_rx_len
-=
4
;
((
uint32_t
*
)
sp
->
cur_rx_buf
)[
0
]
=
__be32_to_cpu
(
data
)
;
return
sizeof
(
data
)
;
}
static
void
spi_ocores_hw_xfer_rx_push
64
(
struct
spi_ocores
*
sp
)
static
size_t
spi_ocores_hw_xfer_rx_pop
64
(
struct
spi_ocores
*
sp
)
{
int
i
;
uint64_t
data
;
for
(
i
=
0
;
i
<
2
;
++
i
)
{
uint32_t
data
;
data
=
spi_ocores_rx_get
(
sp
,
1
)
&
0xFFFFFFFF
;
data
<<=
32
;
data
|=
spi_ocores_rx_get
(
sp
,
0
)
&
0xFFFFFFFF
;
((
uint64_t
*
)
sp
->
cur_rx_buf
)[
0
]
=
__be64_to_cpu
(
data
);
data
=
spi_ocores_rx_get
(
sp
,
i
)
&
0xFFFFFFFF
;
*
((
uint32_t
*
)
sp
->
cur_rx_buf
)
=
data
;
sp
->
cur_rx_buf
+=
4
;
sp
->
cur_rx_len
-=
4
;
}
return
sizeof
(
data
);
}
static
void
spi_ocores_hw_xfer_rx_push
128
(
struct
spi_ocores
*
sp
)
static
size_t
spi_ocores_hw_xfer_rx_pop
128
(
struct
spi_ocores
*
sp
)
{
int
i
;
uint64_t
data
;
for
(
i
=
0
;
i
<
4
;
++
i
)
{
uint32_t
data
;
data
=
spi_ocores_rx_get
(
sp
,
3
)
&
0xFFFFFFFF
;
data
<<=
32
;
data
|=
spi_ocores_rx_get
(
sp
,
2
)
&
0xFFFFFFFF
;
((
uint64_t
*
)
sp
->
cur_rx_buf
)[
1
]
=
__be64_to_cpu
(
data
);
data
=
spi_ocores_rx_get
(
sp
,
i
)
&
0xFFFFFFFF
;
*
((
uint32_t
*
)
sp
->
cur_rx_buf
)
=
data
;
sp
->
cur_rx_buf
+=
4
;
sp
->
cur_rx_len
-=
4
;
}
data
=
spi_ocores_rx_get
(
sp
,
1
)
&
0xFFFFFFFF
;
data
<<=
32
;
data
|=
spi_ocores_rx_get
(
sp
,
0
)
&
0xFFFFFFFF
;
((
uint64_t
*
)
sp
->
cur_rx_buf
)[
0
]
=
__be64_to_cpu
(
data
);
return
sizeof
(
data
)
*
2
;
}
/**
* Write pending data in RX registers
* @sp: SPI OCORE controller
*/
static
void
spi_ocores_hw_xfer_tx_push
(
struct
spi_ocores
*
sp
)
static
size_t
spi_ocores_hw_xfer_rx_pop
(
struct
spi_ocores
*
sp
)
{
size_t
len
=
0
;
uint8_t
nbits
;
/*
* When we read is because a complete HW transfer is over, so we
* can safely decrease the counter of pending bytes
*/
nbits
=
spi_ocores_hw_xfer_bits_per_word
(
sp
);
if
(
nbits
>=
8
)
spi_ocores_hw_xfer_tx_push8
(
sp
);
else
if
(
nbits
>=
16
)
spi_ocores_hw_xfer_tx_push16
(
sp
);
else
if
(
nbits
>=
32
)
spi_ocores_hw_xfer_tx_push32
(
sp
);
else
if
(
nbits
>=
64
)
spi_ocores_hw_xfer_tx_push64
(
sp
);
else
if
(
nbits
>=
128
)
spi_ocores_hw_xfer_tx_push128
(
sp
);
}
sp
->
cur_len
-=
(
nbits
/
8
);
/* FIXME not working for !pow2 */
/**
* Read received data from TX registers
* @sp: SPI OCORE controller
*/
static
void
spi_ocores_hw_xfer_rx_pop
(
struct
spi_ocores
*
sp
)
{
uint8_t
nbits
;
if
(
sp
->
cur_rx_buf
)
len
=
sp
->
cur_rx_pop
(
sp
);
sp
->
cur_rx_buf
+=
len
;
nbits
=
spi_ocores_hw_xfer_bits_per_word
(
sp
);
if
(
nbits
>=
8
)
spi_ocores_hw_xfer_rx_push8
(
sp
);
else
if
(
nbits
>=
16
)
spi_ocores_hw_xfer_rx_push16
(
sp
);
else
if
(
nbits
>=
32
)
spi_ocores_hw_xfer_rx_push32
(
sp
);
else
if
(
nbits
>=
64
)
spi_ocores_hw_xfer_rx_push64
(
sp
);
else
if
(
nbits
>=
128
)
spi_ocores_hw_xfer_rx_push128
(
sp
);
return
len
;
}
static
void
spi_ocores_hw_xfer_start
(
struct
spi_ocores
*
sp
)
{
unsigned
int
cs
=
sp
->
master
->
cur_msg
->
spi
->
chip_select
;
/* Optimize:
* Probably we can avoid to write CTRL DIVIDER and CS everytime
*/
spi_ocores_hw_xfer_config
(
sp
,
sp
->
cur_ctrl
,
sp
->
cur_divider
);
spi_ocores_hw_xfer_cs
(
sp
,
cs
,
1
);
spi_ocores_hw_xfer_go
(
sp
);
}
...
...
@@ -425,13 +414,9 @@ static int spi_ocores_sw_xfer_finish(struct spi_ocores *sp)
spi_ocores_hw_xfer_cs
(
sp
,
cs
,
0
);
}
spi_ocores_hw_xfer_config
(
sp
,
0
,
0
);
sp
->
cur_xfer
=
NULL
;
sp
->
cur_tx_buf
=
NULL
;
sp
->
cur_tx_len
=
0
;
sp
->
cur_rx_buf
=
NULL
;
sp
->
cur_
rx_
len
=
0
;
sp
->
cur_len
=
0
;
return
0
;
}
...
...
@@ -447,17 +432,14 @@ static int spi_ocores_sw_xfer_finish(struct spi_ocores *sp)
static
int
spi_ocores_sw_xfer_next_init
(
struct
spi_ocores
*
sp
)
{
struct
list_head
*
head
=
&
sp
->
master
->
cur_msg
->
transfers
;
uint32_t
hz
;
if
(
spi_ocores_hw_xfer_bits_per_word
(
sp
)
>
128
)
return
-
EINVAL
;
uint8_t
nbits
;
uint16_t
divider
;
uint32_t
hz
,
ctrl
;
if
(
!
sp
->
cur_xfer
)
{
sp
->
cur_xfer
=
list_first_entry_or_null
(
head
,
struct
spi_transfer
,
transfer_list
);
if
(
!
sp
->
cur_xfer
)
return
-
ENODATA
;
}
else
{
if
(
list_is_last
(
&
sp
->
cur_xfer
->
transfer_list
,
head
))
return
-
ENODATA
;
...
...
@@ -465,17 +447,62 @@ static int spi_ocores_sw_xfer_next_init(struct spi_ocores *sp)
sp
->
cur_xfer
=
list_next_entry
(
sp
->
cur_xfer
,
transfer_list
);
}
sp
->
cur_ctrl
=
sp
->
ctrl_base
;
sp
->
cur_ctrl
|=
spi_ocores_hw_xfer_bits_per_word
(
sp
);
if
(
WARN
(
!
sp
->
cur_xfer
,
"Invalid SPI transfer"
))
{
sp
->
master
->
cur_msg
->
status
=
-
EINVAL
;
return
sp
->
master
->
cur_msg
->
status
;
}
nbits
=
spi_ocores_hw_xfer_bits_per_word
(
sp
);
if
((
nbits
-
1
)
&
(
~
SPI_OCORES_CTRL_CHAR_LEN
))
{
sp
->
master
->
cur_msg
->
status
=
-
EINVAL
;
return
sp
->
master
->
cur_msg
->
status
;
}
if
((
sp
->
cur_xfer
->
len
<<
3
)
<
nbits
)
{
dev_err
(
&
sp
->
master
->
dev
,
"Invalid transfer length %d (bits_per_word %d)
\n
"
,
sp
->
cur_xfer
->
len
,
nbits
);
sp
->
master
->
cur_msg
->
status
=
-
EINVAL
;
return
sp
->
master
->
cur_msg
->
status
;
}
ctrl
=
sp
->
ctrl_base
;
if
(
sp
->
master
->
cur_msg
->
spi
->
mode
&
SPI_CPHA
)
{
ctrl
|=
SPI_OCORES_CTRL_Tx_NEG
;
ctrl
|=
SPI_OCORES_CTRL_Rx_NEG
;
}
if
(
sp
->
master
->
cur_msg
->
spi
->
mode
&
SPI_LSB_FIRST
)
ctrl
|=
SPI_OCORES_CTRL_LSB
;
ctrl
|=
nbits
;
if
(
sp
->
cur_xfer
->
speed_hz
)
hz
=
sp
->
cur_xfer
->
speed_hz
;
else
hz
=
sp
->
master
->
cur_msg
->
spi
->
max_speed_hz
;
sp
->
cur_divider
=
1
+
(
sp
->
clock_hz
/
(
hz
*
2
));
divider
=
(
sp
->
clock_hz
/
(
hz
*
2
))
-
1
;
spi_ocores_hw_xfer_config
(
sp
,
ctrl
,
divider
);
sp
->
cur_tx_buf
=
sp
->
cur_xfer
->
tx_buf
;
sp
->
cur_tx_len
=
sp
->
cur_xfer
->
len
;
sp
->
cur_rx_buf
=
sp
->
cur_xfer
->
rx_buf
;
sp
->
cur_rx_len
=
sp
->
cur_xfer
->
len
;
sp
->
cur_len
=
sp
->
cur_xfer
->
len
;
/* set operations */
if
(
nbits
<=
8
)
{
sp
->
cur_tx_push
=
spi_ocores_hw_xfer_tx_push8
;
sp
->
cur_rx_pop
=
spi_ocores_hw_xfer_rx_pop8
;
}
else
if
(
nbits
<=
16
)
{
sp
->
cur_tx_push
=
spi_ocores_hw_xfer_tx_push16
;
sp
->
cur_rx_pop
=
spi_ocores_hw_xfer_rx_pop16
;
}
else
if
(
nbits
<=
32
)
{
sp
->
cur_tx_push
=
spi_ocores_hw_xfer_tx_push32
;
sp
->
cur_rx_pop
=
spi_ocores_hw_xfer_rx_pop32
;
}
else
if
(
nbits
<=
64
)
{
sp
->
cur_tx_push
=
spi_ocores_hw_xfer_tx_push64
;
sp
->
cur_rx_pop
=
spi_ocores_hw_xfer_rx_pop64
;
}
else
if
(
nbits
<=
128
)
{
sp
->
cur_tx_push
=
spi_ocores_hw_xfer_tx_push128
;
sp
->
cur_rx_pop
=
spi_ocores_hw_xfer_rx_pop128
;
}
return
0
;
}
...
...
@@ -491,10 +518,8 @@ static int spi_ocores_sw_xfer_next_start(struct spi_ocores *sp)
int
err
;
err
=
spi_ocores_sw_xfer_next_init
(
sp
);
if
(
err
)
{
spi_finalize_current_message
(
sp
->
master
);
if
(
err
)
return
err
;
}
spi_ocores_hw_xfer_tx_push
(
sp
);
spi_ocores_hw_xfer_start
(
sp
);
...
...
@@ -506,9 +531,49 @@ static int spi_ocores_sw_xfer_next_start(struct spi_ocores *sp)
* @sp: SPI OCORE controller
* Return: True is there are still pending data in the current transfer
*/
static
bool
spi_ocores_sw_xfer_
tx
_pending
(
struct
spi_ocores
*
sp
)
static
bool
spi_ocores_sw_xfer_
has
_pending
(
struct
spi_ocores
*
sp
)
{
return
sp
->
cur_tx_len
;
return
sp
->
cur_len
>
0
;
}
/**
* Finalize message transmission
* @sp: SPI OCORE controller
*/
static
void
spi_ocores_finalize_current_message
(
struct
spi_ocores
*
sp
)
{
unsigned
int
cs
=
sp
->
master
->
cur_msg
->
spi
->
chip_select
;
spi_ocores_hw_xfer_cs
(
sp
,
cs
,
0
);
sp
->
cur_xfer
=
NULL
;
sp
->
master
->
cur_msg
->
status
=
0
;
spi_finalize_current_message
(
sp
->
master
);
}
static
bool
spi_ocores_is_busy
(
struct
spi_ocores
*
sp
)
{
uint32_t
ctrl
=
sp
->
read
(
sp
,
SPI_OCORES_CTRL
);
return
(
ctrl
&
SPI_OCORES_CTRL_BUSY
);
}
/**
* Pop RX word and push next TX from current transfer
* @sp: SPI OCORE controller
*
* Return: 0 on success, -ENODATA when there is nothing to process
*/
static
int
spi_ocores_hw_xfer_rxtx
(
struct
spi_ocores
*
sp
)
{
spi_ocores_hw_xfer_rx_pop
(
sp
);
if
(
spi_ocores_sw_xfer_has_pending
(
sp
))
return
-
ENODATA
;
spi_ocores_hw_xfer_tx_push
(
sp
);
spi_ocores_hw_xfer_start
(
sp
);
return
0
;
}
/**
...
...
@@ -519,18 +584,17 @@ static bool spi_ocores_sw_xfer_tx_pending(struct spi_ocores *sp)
*/
static
int
spi_ocores_process
(
struct
spi_ocores
*
sp
)
{
uint32_t
ctrl
=
sp
->
read
(
sp
,
SPI_OCORES_CTRL
)
;
int
err
;
if
(
ctrl
&
SPI_OCORES_CTRL_BUSY
)
return
-
E
NODATA
;
if
(
spi_ocores_is_busy
(
sp
)
)
return
-
E
BUSY
;
spi_ocores_hw_xfer_rx_pop
(
sp
);
if
(
spi_ocores_sw_xfer_tx_pending
(
sp
))
{
spi_ocores_hw_xfer_tx_push
(
sp
);
spi_ocores_hw_xfer_start
(
sp
);
}
else
{
err
=
spi_ocores_hw_xfer_rxtx
(
sp
);
if
(
err
==
-
ENODATA
)
{
spi_ocores_sw_xfer_finish
(
sp
);
spi_ocores_sw_xfer_next_start
(
sp
);
err
=
spi_ocores_sw_xfer_next_start
(
sp
);
if
(
err
)
spi_ocores_finalize_current_message
(
sp
);
}
return
0
;
...
...
@@ -563,7 +627,7 @@ static irqreturn_t spi_ocores_irq_handler(int irq, void *arg)
int
err
;
err
=
spi_ocores_process
(
sp
);
if
(
err
)
if
(
err
&&
err
!=
-
ENODATA
)
return
IRQ_NONE
;
return
IRQ_HANDLED
;
...
...
@@ -588,6 +652,20 @@ static int spi_ocores_transfer_one_message(struct spi_master *master,
return
0
;
}
/**
* Unprepare hardware
*
* Mainly it disables interrupts
*/
static
int
spi_ocores_unprepare_transfer_hardware
(
struct
spi_master
*
master
)
{
struct
spi_ocores
*
sp
=
spi_master_get_devdata
(
master
);
spi_ocores_hw_xfer_config
(
sp
,
0
,
0
);
return
0
;
}
static
int
spi_ocores_probe
(
struct
platform_device
*
pdev
)
{
struct
spi_master
*
master
;
...
...
@@ -598,7 +676,6 @@ static int spi_ocores_probe(struct platform_device *pdev)
int
irq
;
int
i
;
pr_info
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
master
=
spi_alloc_master
(
&
pdev
->
dev
,
sizeof
(
*
sp
));
if
(
!
master
)
{
dev_err
(
&
pdev
->
dev
,
"failed to allocate spi master
\n
"
);
...
...
@@ -621,8 +698,9 @@ static int spi_ocores_probe(struct platform_device *pdev)
master
->
setup
=
spi_ocores_setup
;
master
->
cleanup
=
spi_ocores_cleanup
;
master
->
transfer_one_message
=
spi_ocores_transfer_one_message
;
master
->
unprepare_transfer_hardware
=
spi_ocores_unprepare_transfer_hardware
;
master
->
num_chipselect
=
SPI_OCORES_CS_MAX_N
;
master
->
bits_per_word_mask
=
BIT
(
32
-
1
)
;
master
->
mode_bits
=
SPI_LSB_FIRST
|
SPI_CPHA
;
if
(
pdata
->
big_endian
)
{
sp
->
read
=
spi_ocores_ioread32be
;
sp
->
write
=
spi_ocores_iowrite32be
;
...
...
@@ -676,16 +754,13 @@ static int spi_ocores_probe(struct platform_device *pdev)
return
0
;
err_reg_spi:
pr_info
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
if
(
!
(
sp
->
flags
&
SPI_OCORES_FLAG_POLL
))
free_irq
(
irq
,
sp
);
err_irq:
err_get_irq:
pr_info
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
devm_iounmap
(
&
pdev
->
dev
,
sp
->
mem
);
err_get_mem:
err_get_pdata:
pr_info
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
spi_master_put
(
master
);
return
err
;
}
...
...
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