sw: first software commit
The software is untested, but it builds. Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
dd14bb4d29
commit
e8aaac5cfe
14
.gitmodules
vendored
14
.gitmodules
vendored
@ -1,21 +1,21 @@
|
||||
[submodule "deps/migen"]
|
||||
path = deps/migen
|
||||
path = hw/deps/migen
|
||||
url = https://github.com/m-labs/migen.git
|
||||
[submodule "deps/litex"]
|
||||
path = deps/litex
|
||||
path = hw/deps/litex
|
||||
url = https://github.com/enjoy-digital/litex.git
|
||||
[submodule "deps/litescope"]
|
||||
path = deps/litescope
|
||||
path = hw/deps/litescope
|
||||
url = https://github.com/enjoy-digital/litescope.git
|
||||
[submodule "deps/pyserial"]
|
||||
path = deps/pyserial
|
||||
path = hw/deps/pyserial
|
||||
url = https://github.com/pyserial/pyserial.git
|
||||
[submodule "deps/litedram"]
|
||||
path = deps/litedram
|
||||
path = hw/deps/litedram
|
||||
url = https://github.com/enjoy-digital/litedram.git
|
||||
[submodule "deps/valentyusb"]
|
||||
path = deps/valentyusb
|
||||
path = hw/deps/valentyusb
|
||||
url = https://github.com/im-tomu/valentyusb.git
|
||||
[submodule "deps/lxsocsupport"]
|
||||
path = deps/lxsocsupport
|
||||
path = hw/deps/lxsocsupport
|
||||
url = https://github.com/xobs/lxsocsupport.git
|
||||
|
@ -87,7 +87,8 @@ _io_evt = [
|
||||
),
|
||||
("clk48", 0, Pins("44"), IOStandard("LVCMOS33"))
|
||||
]
|
||||
_io_dvt = [
|
||||
|
||||
_io_pvt = [
|
||||
("serial", 0,
|
||||
Subsignal("rx", Pins("C3")),
|
||||
Subsignal("tx", Pins("B3"), Misc("PULLUP")),
|
||||
@ -125,6 +126,7 @@ _io_dvt = [
|
||||
),
|
||||
("clk48", 0, Pins("F4"), IOStandard("LVCMOS33"))
|
||||
]
|
||||
|
||||
_io_hacker = [
|
||||
("serial", 0,
|
||||
Subsignal("rx", Pins("C3")),
|
||||
@ -197,7 +199,6 @@ class _CRG(Module):
|
||||
]
|
||||
|
||||
if use_pll:
|
||||
|
||||
# Divide clk48 down to clk12, to ensure they're synchronized.
|
||||
# By doing this, we avoid needing clock-domain crossing.
|
||||
clk12_counter = Signal(2)
|
||||
@ -316,12 +317,12 @@ class Platform(LatticePlatform):
|
||||
def __init__(self, revision=None, toolchain="icestorm"):
|
||||
if revision == "evt":
|
||||
LatticePlatform.__init__(self, "ice40-up5k-sg48", _io_evt, _connectors, toolchain="icestorm")
|
||||
elif revision == "dvt":
|
||||
LatticePlatform.__init__(self, "ice40-up5k-uwg30", _io_dvt, _connectors, toolchain="icestorm")
|
||||
elif revision == "pvt" or revision == "dvt":
|
||||
LatticePlatform.__init__(self, "ice40-up5k-uwg30", _io_pvt, _connectors, toolchain="icestorm")
|
||||
elif revision == "hacker":
|
||||
LatticePlatform.__init__(self, "ice40-up5k-uwg30", _io_hacker, _connectors, toolchain="icestorm")
|
||||
else:
|
||||
raise ValueError("Unrecognized reivsion: {}. Known values: evt, dvt, hacker".format(revision))
|
||||
raise ValueError("Unrecognized reivsion: {}. Known values: evt, dvt, pvt, hacker".format(revision))
|
||||
|
||||
def create_programmer(self):
|
||||
raise ValueError("programming is not supported")
|
||||
@ -593,8 +594,14 @@ class Version(Module, AutoCSR):
|
||||
stderr=subprocess.PIPE)
|
||||
(git_stdout, _) = git_rev_cmd.communicate()
|
||||
if git_rev_cmd.wait() != 0:
|
||||
print('unable to get git version')
|
||||
return
|
||||
git_rev_cmd = subprocess.Popen(["git", "rev-parse", "HEAD"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
(git_stdout, _) = git_rev_cmd.communicate()
|
||||
if git_rev_cmd.wait() != 0:
|
||||
print('WARNING: unable to get git version')
|
||||
return (0, 0, 0, 0, 0, False)
|
||||
return (0, 0, 0, makeint(git_stdout[0:8], 16), 0, False)
|
||||
raw_git_rev = git_stdout.decode().strip()
|
||||
|
||||
dirty = False
|
||||
@ -773,8 +780,6 @@ class BaseSoC(SoCCore):
|
||||
pulldown = TSTriple()
|
||||
self.specials += pulldown.get_tristate(usb_pads.pulldown)
|
||||
self.comb += pulldown.oe.eq(0)
|
||||
# self.submodules.usb = epmem.MemInterface(usb_iobuf)
|
||||
# self.submodules.usb = unififo.UsbUniFifo(usb_iobuf)
|
||||
|
||||
# Add GPIO pads for the touch buttons
|
||||
self.submodules.touch = TouchPads(platform.request("touch"))
|
||||
@ -784,7 +789,7 @@ class BaseSoC(SoCCore):
|
||||
# and the "-dffe_min_ce_use 4" flag prevents Yosys from generating a
|
||||
# Clock Enable signal for a LUT that has fewer than 4 flip-flops.
|
||||
# This increases density, and lets us use the FPGA more efficiently.
|
||||
platform.toolchain.nextpnr_yosys_template[2] += " -relut -dffe_min_ce_use 5"
|
||||
platform.toolchain.nextpnr_yosys_template[2] += " -relut -dffe_min_ce_use 4"
|
||||
if use_dsp:
|
||||
platform.toolchain.nextpnr_yosys_template[2] += " -dsp"
|
||||
|
||||
@ -813,7 +818,7 @@ def main():
|
||||
help="where to have the CPU obtain its executable code from"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--revision", choices=["dvt", "evt", "hacker"], required=True,
|
||||
"--revision", choices=["pvt", "dvt", "evt", "hacker"], required=True,
|
||||
help="build foboot for a particular hardware revision"
|
||||
)
|
||||
parser.add_argument(
|
||||
@ -834,35 +839,10 @@ def main():
|
||||
parser.add_argument(
|
||||
"--placer", choices=["sa", "heap"], help="which placer to use in nextpnr"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--export-random-rom-file", help="Generate a random ROM file and save it to a file"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
output_dir = 'build'
|
||||
|
||||
if args.export_random_rom_file is not None:
|
||||
size = 0x2000
|
||||
def xorshift32(x):
|
||||
x = x ^ (x << 13) & 0xffffffff
|
||||
x = x ^ (x >> 17) & 0xffffffff
|
||||
x = x ^ (x << 5) & 0xffffffff
|
||||
return x & 0xffffffff
|
||||
|
||||
def get_rand(x):
|
||||
out = 0
|
||||
for i in range(32):
|
||||
x = xorshift32(x)
|
||||
if (x & 1) == 1:
|
||||
out = out | (1 << i)
|
||||
return out & 0xffffffff
|
||||
seed = 1
|
||||
with open(args.export_random_rom_file, "w", newline="\n") as output:
|
||||
for d in range(int(size / 4)):
|
||||
seed = get_rand(seed)
|
||||
print("{:08x}".format(seed), file=output)
|
||||
return 0
|
||||
|
||||
compile_software = False
|
||||
if args.boot_source == "bios" and args.bios is None:
|
||||
compile_software = True
|
3578
hw/rtl/2-stage-1024-cache-debug.v
Normal file
3578
hw/rtl/2-stage-1024-cache-debug.v
Normal file
File diff suppressed because it is too large
Load Diff
5
hw/rtl/2-stage-1024-cache-debug.yaml
Normal file
5
hw/rtl/2-stage-1024-cache-debug.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}
|
||||
iBus: !!vexriscv.BusReport
|
||||
flushInstructions: [4111, 19, 19, 19]
|
||||
info: !!vexriscv.CacheReport {bytePerLine: 32, size: 1024}
|
||||
kind: cached
|
3289
hw/rtl/2-stage-1024-cache.v
Normal file
3289
hw/rtl/2-stage-1024-cache.v
Normal file
File diff suppressed because it is too large
Load Diff
4
hw/rtl/2-stage-1024-cache.yaml
Normal file
4
hw/rtl/2-stage-1024-cache.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
iBus: !!vexriscv.BusReport
|
||||
flushInstructions: [4111, 19, 19, 19]
|
||||
info: !!vexriscv.CacheReport {bytePerLine: 32, size: 1024}
|
||||
kind: cached
|
3578
hw/rtl/2-stage-2048-cache-debug.v
Normal file
3578
hw/rtl/2-stage-2048-cache-debug.v
Normal file
File diff suppressed because it is too large
Load Diff
5
hw/rtl/2-stage-2048-cache-debug.yaml
Normal file
5
hw/rtl/2-stage-2048-cache-debug.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}
|
||||
iBus: !!vexriscv.BusReport
|
||||
flushInstructions: [4111, 19, 19, 19]
|
||||
info: !!vexriscv.CacheReport {bytePerLine: 32, size: 2048}
|
||||
kind: cached
|
3297
hw/rtl/2-stage-2048-cache.v
Normal file
3297
hw/rtl/2-stage-2048-cache.v
Normal file
File diff suppressed because it is too large
Load Diff
4
hw/rtl/2-stage-2048-cache.yaml
Normal file
4
hw/rtl/2-stage-2048-cache.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
iBus: !!vexriscv.BusReport
|
||||
flushInstructions: [4111, 19, 19, 19]
|
||||
info: !!vexriscv.CacheReport {bytePerLine: 32, size: 2048}
|
||||
kind: cached
|
3769
hw/rtl/2-stage-512-cache-debug.v
Normal file
3769
hw/rtl/2-stage-512-cache-debug.v
Normal file
File diff suppressed because it is too large
Load Diff
5
hw/rtl/2-stage-512-cache-debug.yaml
Normal file
5
hw/rtl/2-stage-512-cache-debug.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}
|
||||
iBus: !!vexriscv.BusReport
|
||||
flushInstructions: [16399, 19, 19, 19]
|
||||
info: !!vexriscv.CacheReport {bytePerLine: 32, size: 512}
|
||||
kind: cached
|
3499
hw/rtl/2-stage-no-cache-debug.v
Normal file
3499
hw/rtl/2-stage-no-cache-debug.v
Normal file
File diff suppressed because it is too large
Load Diff
1
hw/rtl/2-stage-no-cache-debug.yaml
Normal file
1
hw/rtl/2-stage-no-cache-debug.yaml
Normal file
@ -0,0 +1 @@
|
||||
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}
|
3965
hw/rtl/4-stage-1024-cache-debug.v
Normal file
3965
hw/rtl/4-stage-1024-cache-debug.v
Normal file
File diff suppressed because it is too large
Load Diff
5
hw/rtl/4-stage-1024-cache-debug.yaml
Normal file
5
hw/rtl/4-stage-1024-cache-debug.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}
|
||||
iBus: !!vexriscv.BusReport
|
||||
flushInstructions: [4111, 19, 19, 19]
|
||||
info: !!vexriscv.CacheReport {bytePerLine: 32, size: 1024}
|
||||
kind: cached
|
3865
hw/rtl/4-stage-no-cache-debug.v
Normal file
3865
hw/rtl/4-stage-no-cache-debug.v
Normal file
File diff suppressed because it is too large
Load Diff
1
hw/rtl/4-stage-no-cache-debug.yaml
Normal file
1
hw/rtl/4-stage-no-cache-debug.yaml
Normal file
@ -0,0 +1 @@
|
||||
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}
|
3902
hw/rtl/5-stage-pipelined-no-cache-debug.v
Normal file
3902
hw/rtl/5-stage-pipelined-no-cache-debug.v
Normal file
File diff suppressed because it is too large
Load Diff
1
hw/rtl/5-stage-pipelined-no-cache-debug.yaml
Normal file
1
hw/rtl/5-stage-pipelined-no-cache-debug.yaml
Normal file
@ -0,0 +1 @@
|
||||
debug: !!vexriscv.DebugReport {hardwareBreakpointCount: 4}
|
579
hw/rtl/spimemio.v
Normal file
579
hw/rtl/spimemio.v
Normal file
@ -0,0 +1,579 @@
|
||||
/*
|
||||
* PicoSoC - A simple example SoC using PicoRV32
|
||||
*
|
||||
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
module spimemio (
|
||||
input clk, resetn,
|
||||
|
||||
input valid,
|
||||
output ready,
|
||||
input [23:0] addr,
|
||||
output reg [31:0] rdata,
|
||||
|
||||
output flash_csb,
|
||||
output flash_clk,
|
||||
|
||||
output flash_io0_oe,
|
||||
output flash_io1_oe,
|
||||
output flash_io2_oe,
|
||||
output flash_io3_oe,
|
||||
|
||||
output flash_io0_do,
|
||||
output flash_io1_do,
|
||||
output flash_io2_do,
|
||||
output flash_io3_do,
|
||||
|
||||
input flash_io0_di,
|
||||
input flash_io1_di,
|
||||
input flash_io2_di,
|
||||
input flash_io3_di,
|
||||
|
||||
input [3:0] cfgreg_we,
|
||||
input [31:0] cfgreg_di,
|
||||
output [31:0] cfgreg_do
|
||||
);
|
||||
reg xfer_resetn;
|
||||
reg din_valid;
|
||||
wire din_ready;
|
||||
reg [7:0] din_data;
|
||||
reg [3:0] din_tag;
|
||||
reg din_cont;
|
||||
reg din_qspi;
|
||||
reg din_ddr;
|
||||
reg din_rd;
|
||||
|
||||
wire dout_valid;
|
||||
wire [7:0] dout_data;
|
||||
wire [3:0] dout_tag;
|
||||
|
||||
reg [23:0] buffer;
|
||||
|
||||
reg [23:0] rd_addr;
|
||||
reg rd_valid;
|
||||
reg rd_wait;
|
||||
reg rd_inc;
|
||||
|
||||
assign ready = valid && (addr == rd_addr) && rd_valid;
|
||||
wire jump = valid && !ready && (addr != rd_addr+4) && rd_valid;
|
||||
|
||||
reg softreset;
|
||||
|
||||
reg config_en; // cfgreg[31]
|
||||
reg config_ddr; // cfgreg[22]
|
||||
reg config_qspi; // cfgreg[21]
|
||||
reg config_cont; // cfgreg[20]
|
||||
reg [3:0] config_dummy; // cfgreg[19:16]
|
||||
reg [3:0] config_oe; // cfgreg[11:8]
|
||||
reg config_csb; // cfgreg[5]
|
||||
reg config_clk; // cfgref[4]
|
||||
reg [3:0] config_do; // cfgreg[3:0]
|
||||
|
||||
assign cfgreg_do[31] = config_en;
|
||||
assign cfgreg_do[30:23] = 0;
|
||||
assign cfgreg_do[22] = config_ddr;
|
||||
assign cfgreg_do[21] = config_qspi;
|
||||
assign cfgreg_do[20] = config_cont;
|
||||
assign cfgreg_do[19:16] = config_dummy;
|
||||
assign cfgreg_do[15:12] = 0;
|
||||
assign cfgreg_do[11:8] = {flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe};
|
||||
assign cfgreg_do[7:6] = 0;
|
||||
assign cfgreg_do[5] = flash_csb;
|
||||
assign cfgreg_do[4] = flash_clk;
|
||||
assign cfgreg_do[3:0] = {flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di};
|
||||
|
||||
always @(posedge clk) begin
|
||||
softreset <= !config_en || cfgreg_we;
|
||||
if (!resetn) begin
|
||||
softreset <= 1;
|
||||
config_en <= 1;
|
||||
config_csb <= 0;
|
||||
config_clk <= 0;
|
||||
config_oe <= 0;
|
||||
config_do <= 0;
|
||||
config_ddr <= 0;
|
||||
config_qspi <= 0;
|
||||
config_cont <= 0;
|
||||
config_dummy <= 8;
|
||||
end else begin
|
||||
if (cfgreg_we[0]) begin
|
||||
config_csb <= cfgreg_di[5];
|
||||
config_clk <= cfgreg_di[4];
|
||||
config_do <= cfgreg_di[3:0];
|
||||
end
|
||||
if (cfgreg_we[1]) begin
|
||||
config_oe <= cfgreg_di[11:8];
|
||||
end
|
||||
if (cfgreg_we[2]) begin
|
||||
config_ddr <= cfgreg_di[22];
|
||||
config_qspi <= cfgreg_di[21];
|
||||
config_cont <= cfgreg_di[20];
|
||||
config_dummy <= cfgreg_di[19:16];
|
||||
end
|
||||
if (cfgreg_we[3]) begin
|
||||
config_en <= cfgreg_di[31];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
wire xfer_csb;
|
||||
wire xfer_clk;
|
||||
|
||||
wire xfer_io0_oe;
|
||||
wire xfer_io1_oe;
|
||||
wire xfer_io2_oe;
|
||||
wire xfer_io3_oe;
|
||||
|
||||
wire xfer_io0_do;
|
||||
wire xfer_io1_do;
|
||||
wire xfer_io2_do;
|
||||
wire xfer_io3_do;
|
||||
|
||||
reg xfer_io0_90;
|
||||
reg xfer_io1_90;
|
||||
reg xfer_io2_90;
|
||||
reg xfer_io3_90;
|
||||
|
||||
always @(negedge clk) begin
|
||||
xfer_io0_90 <= xfer_io0_do;
|
||||
xfer_io1_90 <= xfer_io1_do;
|
||||
xfer_io2_90 <= xfer_io2_do;
|
||||
xfer_io3_90 <= xfer_io3_do;
|
||||
end
|
||||
|
||||
assign flash_csb = config_en ? xfer_csb : config_csb;
|
||||
assign flash_clk = config_en ? xfer_clk : config_clk;
|
||||
|
||||
assign flash_io0_oe = config_en ? xfer_io0_oe : config_oe[0];
|
||||
assign flash_io1_oe = config_en ? xfer_io1_oe : config_oe[1];
|
||||
assign flash_io2_oe = config_en ? xfer_io2_oe : config_oe[2];
|
||||
assign flash_io3_oe = config_en ? xfer_io3_oe : config_oe[3];
|
||||
|
||||
assign flash_io0_do = config_en ? (config_ddr ? xfer_io0_90 : xfer_io0_do) : config_do[0];
|
||||
assign flash_io1_do = config_en ? (config_ddr ? xfer_io1_90 : xfer_io1_do) : config_do[1];
|
||||
assign flash_io2_do = config_en ? (config_ddr ? xfer_io2_90 : xfer_io2_do) : config_do[2];
|
||||
assign flash_io3_do = config_en ? (config_ddr ? xfer_io3_90 : xfer_io3_do) : config_do[3];
|
||||
|
||||
wire xfer_dspi = din_ddr && !din_qspi;
|
||||
wire xfer_ddr = din_ddr && din_qspi;
|
||||
|
||||
spimemio_xfer xfer (
|
||||
.clk (clk ),
|
||||
.resetn (xfer_resetn ),
|
||||
.din_valid (din_valid ),
|
||||
.din_ready (din_ready ),
|
||||
.din_data (din_data ),
|
||||
.din_tag (din_tag ),
|
||||
.din_cont (din_cont ),
|
||||
.din_dspi (xfer_dspi ),
|
||||
.din_qspi (din_qspi ),
|
||||
.din_ddr (xfer_ddr ),
|
||||
.din_rd (din_rd ),
|
||||
.dout_valid (dout_valid ),
|
||||
.dout_data (dout_data ),
|
||||
.dout_tag (dout_tag ),
|
||||
.flash_csb (xfer_csb ),
|
||||
.flash_clk (xfer_clk ),
|
||||
.flash_io0_oe (xfer_io0_oe ),
|
||||
.flash_io1_oe (xfer_io1_oe ),
|
||||
.flash_io2_oe (xfer_io2_oe ),
|
||||
.flash_io3_oe (xfer_io3_oe ),
|
||||
.flash_io0_do (xfer_io0_do ),
|
||||
.flash_io1_do (xfer_io1_do ),
|
||||
.flash_io2_do (xfer_io2_do ),
|
||||
.flash_io3_do (xfer_io3_do ),
|
||||
.flash_io0_di (flash_io0_di),
|
||||
.flash_io1_di (flash_io1_di),
|
||||
.flash_io2_di (flash_io2_di),
|
||||
.flash_io3_di (flash_io3_di)
|
||||
);
|
||||
|
||||
reg [3:0] state;
|
||||
|
||||
always @(posedge clk) begin
|
||||
xfer_resetn <= 1;
|
||||
din_valid <= 0;
|
||||
|
||||
if (!resetn || softreset) begin
|
||||
state <= 0;
|
||||
xfer_resetn <= 0;
|
||||
rd_valid <= 0;
|
||||
din_tag <= 0;
|
||||
din_cont <= 0;
|
||||
din_qspi <= 0;
|
||||
din_ddr <= 0;
|
||||
din_rd <= 0;
|
||||
end else begin
|
||||
if (dout_valid && dout_tag == 1) buffer[ 7: 0] <= dout_data;
|
||||
if (dout_valid && dout_tag == 2) buffer[15: 8] <= dout_data;
|
||||
if (dout_valid && dout_tag == 3) buffer[23:16] <= dout_data;
|
||||
if (dout_valid && dout_tag == 4) begin
|
||||
rdata <= {dout_data, buffer};
|
||||
rd_addr <= rd_inc ? rd_addr + 4 : addr;
|
||||
rd_valid <= 1;
|
||||
rd_wait <= rd_inc;
|
||||
rd_inc <= 1;
|
||||
end
|
||||
|
||||
if (valid)
|
||||
rd_wait <= 0;
|
||||
|
||||
case (state)
|
||||
0: begin
|
||||
din_valid <= 1;
|
||||
din_data <= 8'h ff;
|
||||
din_tag <= 0;
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
state <= 1;
|
||||
end
|
||||
end
|
||||
1: begin
|
||||
if (dout_valid) begin
|
||||
xfer_resetn <= 0;
|
||||
state <= 2;
|
||||
end
|
||||
end
|
||||
2: begin
|
||||
din_valid <= 1;
|
||||
din_data <= 8'h ab;
|
||||
din_tag <= 0;
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
state <= 3;
|
||||
end
|
||||
end
|
||||
3: begin
|
||||
if (dout_valid) begin
|
||||
xfer_resetn <= 0;
|
||||
state <= 4;
|
||||
end
|
||||
end
|
||||
4: begin
|
||||
rd_inc <= 0;
|
||||
din_valid <= 1;
|
||||
din_tag <= 0;
|
||||
case ({config_ddr, config_qspi})
|
||||
2'b11: din_data <= 8'h ED;
|
||||
2'b01: din_data <= 8'h EB;
|
||||
2'b10: din_data <= 8'h BB;
|
||||
2'b00: din_data <= 8'h 03;
|
||||
endcase
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
state <= 5;
|
||||
end
|
||||
end
|
||||
5: begin
|
||||
if (valid && !ready) begin
|
||||
din_valid <= 1;
|
||||
din_tag <= 0;
|
||||
din_data <= addr[23:16];
|
||||
din_qspi <= config_qspi;
|
||||
din_ddr <= config_ddr;
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
state <= 6;
|
||||
end
|
||||
end
|
||||
end
|
||||
6: begin
|
||||
din_valid <= 1;
|
||||
din_tag <= 0;
|
||||
din_data <= addr[15:8];
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
state <= 7;
|
||||
end
|
||||
end
|
||||
7: begin
|
||||
din_valid <= 1;
|
||||
din_tag <= 0;
|
||||
din_data <= addr[7:0];
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
din_data <= 0;
|
||||
state <= config_qspi || config_ddr ? 8 : 9;
|
||||
end
|
||||
end
|
||||
8: begin
|
||||
din_valid <= 1;
|
||||
din_tag <= 0;
|
||||
din_data <= config_cont ? 8'h A5 : 8'h FF;
|
||||
if (din_ready) begin
|
||||
din_rd <= 1;
|
||||
din_data <= config_dummy;
|
||||
din_valid <= 0;
|
||||
state <= 9;
|
||||
end
|
||||
end
|
||||
9: begin
|
||||
din_valid <= 1;
|
||||
din_tag <= 1;
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
state <= 10;
|
||||
end
|
||||
end
|
||||
10: begin
|
||||
din_valid <= 1;
|
||||
din_data <= 8'h 00;
|
||||
din_tag <= 2;
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
state <= 11;
|
||||
end
|
||||
end
|
||||
11: begin
|
||||
din_valid <= 1;
|
||||
din_tag <= 3;
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
state <= 12;
|
||||
end
|
||||
end
|
||||
12: begin
|
||||
if (!rd_wait || valid) begin
|
||||
din_valid <= 1;
|
||||
din_tag <= 4;
|
||||
if (din_ready) begin
|
||||
din_valid <= 0;
|
||||
state <= 9;
|
||||
end
|
||||
end
|
||||
end
|
||||
endcase
|
||||
|
||||
if (jump) begin
|
||||
rd_inc <= 0;
|
||||
rd_valid <= 0;
|
||||
xfer_resetn <= 0;
|
||||
if (config_cont) begin
|
||||
state <= 5;
|
||||
end else begin
|
||||
state <= 4;
|
||||
din_qspi <= 0;
|
||||
din_ddr <= 0;
|
||||
end
|
||||
din_rd <= 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
||||
module spimemio_xfer (
|
||||
input clk, resetn,
|
||||
|
||||
input din_valid,
|
||||
output din_ready,
|
||||
input [7:0] din_data,
|
||||
input [3:0] din_tag,
|
||||
input din_cont,
|
||||
input din_dspi,
|
||||
input din_qspi,
|
||||
input din_ddr,
|
||||
input din_rd,
|
||||
|
||||
output dout_valid,
|
||||
output [7:0] dout_data,
|
||||
output [3:0] dout_tag,
|
||||
|
||||
output reg flash_csb,
|
||||
output reg flash_clk,
|
||||
|
||||
output reg flash_io0_oe,
|
||||
output reg flash_io1_oe,
|
||||
output reg flash_io2_oe,
|
||||
output reg flash_io3_oe,
|
||||
|
||||
output reg flash_io0_do,
|
||||
output reg flash_io1_do,
|
||||
output reg flash_io2_do,
|
||||
output reg flash_io3_do,
|
||||
|
||||
input flash_io0_di,
|
||||
input flash_io1_di,
|
||||
input flash_io2_di,
|
||||
input flash_io3_di
|
||||
);
|
||||
reg [7:0] obuffer;
|
||||
reg [7:0] ibuffer;
|
||||
|
||||
reg [3:0] count;
|
||||
reg [3:0] dummy_count;
|
||||
|
||||
reg xfer_cont;
|
||||
reg xfer_dspi;
|
||||
reg xfer_qspi;
|
||||
reg xfer_ddr;
|
||||
reg xfer_ddr_q;
|
||||
reg xfer_rd;
|
||||
reg [3:0] xfer_tag;
|
||||
reg [3:0] xfer_tag_q;
|
||||
|
||||
reg [7:0] next_obuffer;
|
||||
reg [7:0] next_ibuffer;
|
||||
reg [3:0] next_count;
|
||||
|
||||
reg fetch;
|
||||
reg next_fetch;
|
||||
reg last_fetch;
|
||||
|
||||
always @(posedge clk) begin
|
||||
xfer_ddr_q <= xfer_ddr;
|
||||
xfer_tag_q <= xfer_tag;
|
||||
end
|
||||
|
||||
assign din_ready = din_valid && resetn && next_fetch;
|
||||
|
||||
assign dout_valid = (xfer_ddr_q ? fetch && !last_fetch : next_fetch && !fetch) && resetn;
|
||||
assign dout_data = ibuffer;
|
||||
assign dout_tag = xfer_tag_q;
|
||||
|
||||
always @* begin
|
||||
flash_io0_oe = 0;
|
||||
flash_io1_oe = 0;
|
||||
flash_io2_oe = 0;
|
||||
flash_io3_oe = 0;
|
||||
|
||||
flash_io0_do = 0;
|
||||
flash_io1_do = 0;
|
||||
flash_io2_do = 0;
|
||||
flash_io3_do = 0;
|
||||
|
||||
next_obuffer = obuffer;
|
||||
next_ibuffer = ibuffer;
|
||||
next_count = count;
|
||||
next_fetch = 0;
|
||||
|
||||
if (dummy_count == 0) begin
|
||||
casez ({xfer_ddr, xfer_qspi, xfer_dspi})
|
||||
3'b 000: begin
|
||||
flash_io0_oe = 1;
|
||||
flash_io0_do = obuffer[7];
|
||||
|
||||
if (flash_clk) begin
|
||||
next_obuffer = {obuffer[6:0], 1'b 0};
|
||||
next_count = count - |count;
|
||||
end else begin
|
||||
next_ibuffer = {ibuffer[6:0], flash_io1_di};
|
||||
end
|
||||
|
||||
next_fetch = (next_count == 0);
|
||||
end
|
||||
3'b 01?: begin
|
||||
flash_io0_oe = !xfer_rd;
|
||||
flash_io1_oe = !xfer_rd;
|
||||
flash_io2_oe = !xfer_rd;
|
||||
flash_io3_oe = !xfer_rd;
|
||||
|
||||
flash_io0_do = obuffer[4];
|
||||
flash_io1_do = obuffer[5];
|
||||
flash_io2_do = obuffer[6];
|
||||
flash_io3_do = obuffer[7];
|
||||
|
||||
if (flash_clk) begin
|
||||
next_obuffer = {obuffer[3:0], 4'b 0000};
|
||||
next_count = count - {|count, 2'b00};
|
||||
end else begin
|
||||
next_ibuffer = {ibuffer[3:0], flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di};
|
||||
end
|
||||
|
||||
next_fetch = (next_count == 0);
|
||||
end
|
||||
3'b 11?: begin
|
||||
flash_io0_oe = !xfer_rd;
|
||||
flash_io1_oe = !xfer_rd;
|
||||
flash_io2_oe = !xfer_rd;
|
||||
flash_io3_oe = !xfer_rd;
|
||||
|
||||
flash_io0_do = obuffer[4];
|
||||
flash_io1_do = obuffer[5];
|
||||
flash_io2_do = obuffer[6];
|
||||
flash_io3_do = obuffer[7];
|
||||
|
||||
next_obuffer = {obuffer[3:0], 4'b 0000};
|
||||
next_ibuffer = {ibuffer[3:0], flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di};
|
||||
next_count = count - {|count, 2'b00};
|
||||
|
||||
next_fetch = (next_count == 0);
|
||||
end
|
||||
3'b ??1: begin
|
||||
flash_io0_oe = !xfer_rd;
|
||||
flash_io1_oe = !xfer_rd;
|
||||
|
||||
flash_io0_do = obuffer[6];
|
||||
flash_io1_do = obuffer[7];
|
||||
|
||||
if (flash_clk) begin
|
||||
next_obuffer = {obuffer[5:0], 2'b 00};
|
||||
next_count = count - {|count, 1'b0};
|
||||
end else begin
|
||||
next_ibuffer = {ibuffer[5:0], flash_io1_di, flash_io0_di};
|
||||
end
|
||||
|
||||
next_fetch = (next_count == 0);
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (!resetn) begin
|
||||
fetch <= 1;
|
||||
last_fetch <= 1;
|
||||
flash_csb <= 1;
|
||||
flash_clk <= 0;
|
||||
count <= 0;
|
||||
dummy_count <= 0;
|
||||
xfer_tag <= 0;
|
||||
xfer_cont <= 0;
|
||||
xfer_dspi <= 0;
|
||||
xfer_qspi <= 0;
|
||||
xfer_ddr <= 0;
|
||||
xfer_rd <= 0;
|
||||
end else begin
|
||||
fetch <= next_fetch;
|
||||
last_fetch <= xfer_ddr ? fetch : 1;
|
||||
if (dummy_count) begin
|
||||
flash_clk <= !flash_clk && !flash_csb;
|
||||
dummy_count <= dummy_count - flash_clk;
|
||||
end else
|
||||
if (count) begin
|
||||
flash_clk <= !flash_clk && !flash_csb;
|
||||
obuffer <= next_obuffer;
|
||||
ibuffer <= next_ibuffer;
|
||||
count <= next_count;
|
||||
end
|
||||
if (din_valid && din_ready) begin
|
||||
flash_csb <= 0;
|
||||
flash_clk <= 0;
|
||||
|
||||
count <= 8;
|
||||
dummy_count <= din_rd ? din_data : 0;
|
||||
obuffer <= din_data;
|
||||
|
||||
xfer_tag <= din_tag;
|
||||
xfer_cont <= din_cont;
|
||||
xfer_dspi <= din_dspi;
|
||||
xfer_qspi <= din_qspi;
|
||||
xfer_ddr <= din_ddr;
|
||||
xfer_rd <= din_rd;
|
||||
end
|
||||
end
|
||||
end
|
||||
endmodule
|
131
sw/Makefile
Normal file
131
sw/Makefile
Normal file
@ -0,0 +1,131 @@
|
||||
GIT_VERSION := $(shell git describe --tags)
|
||||
|
||||
# There is no 64-bit gcc on Raspberry Pi, so use the 32-bit version
|
||||
ifneq (,$(wildcard /etc/rpi-issue))
|
||||
TRGT ?= riscv32-unknown-elf-
|
||||
else
|
||||
TRGT ?= riscv64-unknown-elf-
|
||||
endif
|
||||
|
||||
CC := $(TRGT)gcc
|
||||
CXX := $(TRGT)g++
|
||||
OBJCOPY := $(TRGT)objcopy
|
||||
|
||||
RM := rm -rf
|
||||
COPY := cp -a
|
||||
PATH_SEP := /
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
COPY := copy
|
||||
RM := del
|
||||
PATH_SEP := \\
|
||||
endif
|
||||
|
||||
ifeq ($(LITEX),1)
|
||||
BASE_DIR := ../../../../sw
|
||||
LDSCRIPT := $(BASE_DIR)/ld/linker.ld
|
||||
LD_DIR := ../include/generated
|
||||
ADD_CFLAGS := -I../include -I$(BASE_DIR)/include
|
||||
ADD_LFLAGS :=
|
||||
PACKAGE := bios
|
||||
else
|
||||
BASE_DIR := .
|
||||
LD_DIR := $(BASE_DIR)/ld
|
||||
LDSCRIPT := $(BASE_DIR)/ld/linker.ld
|
||||
ADD_CFLAGS := -I$(BASE_DIR)/include
|
||||
ADD_LFLAGS :=
|
||||
PACKAGE := factory-test
|
||||
endif
|
||||
|
||||
LDSCRIPTS := $(LDSCRIPT) $(LD_DIR)/output_format.ld $(LD_DIR)/regions.ld
|
||||
SRC_DIR := $(BASE_DIR)/src
|
||||
THIRD_PARTY := $(BASE_DIR)/third_party
|
||||
DBG_CFLAGS := -ggdb -g -DDEBUG -Wall
|
||||
DBG_LFLAGS := -ggdb -g -Wall
|
||||
CFLAGS := $(ADD_CFLAGS) \
|
||||
-D__vexriscv__ -march=rv32i -mabi=ilp32 \
|
||||
-Wall -Wextra \
|
||||
-flto \
|
||||
-ffunction-sections -fdata-sections -fno-common \
|
||||
-fomit-frame-pointer -Os \
|
||||
-march=rv32i \
|
||||
-DGIT_VERSION=u\"$(GIT_VERSION)\" -std=gnu11
|
||||
CXXFLAGS := $(CFLAGS) -std=c++11 -fno-rtti -fno-exceptions
|
||||
LFLAGS := $(CFLAGS) $(ADD_LFLAGS) -L$(LD_DIR) \
|
||||
-nostartfiles \
|
||||
-nostdlib \
|
||||
-Wl,--gc-sections \
|
||||
-Wl,--no-warn-mismatch \
|
||||
-Wl,--script=$(LDSCRIPT) \
|
||||
-Wl,--build-id=none
|
||||
|
||||
OBJ_DIR := .obj
|
||||
|
||||
CSOURCES := $(wildcard $(SRC_DIR)/*.c)
|
||||
CPPSOURCES := $(wildcard $(SRC_DIR)/*.cpp)
|
||||
ASOURCES := $(wildcard $(SRC_DIR)/*.S)
|
||||
COBJS := $(addprefix $(OBJ_DIR)/, $(notdir $(CSOURCES:.c=.o)))
|
||||
CXXOBJS := $(addprefix $(OBJ_DIR)/, $(notdir $(CPPSOURCES:.cpp=.o)))
|
||||
AOBJS := $(addprefix $(OBJ_DIR)/, $(notdir $(ASOURCES:.S=.o)))
|
||||
OBJECTS := $(COBJS) $(CXXOBJS) $(AOBJS)
|
||||
VPATH := $(SRC_DIR)
|
||||
|
||||
QUIET := @
|
||||
|
||||
ALL := all
|
||||
TARGET := $(PACKAGE).elf
|
||||
CLEAN := clean
|
||||
|
||||
$(ALL): $(TARGET) $(PACKAGE).bin $(PACKAGE).ihex
|
||||
|
||||
$(OBJECTS): | $(OBJ_DIR)
|
||||
|
||||
$(TARGET): $(OBJECTS) $(LDSCRIPTS)
|
||||
$(QUIET) echo " LD $@"
|
||||
$(QUIET) $(CC) $(OBJECTS) $(LFLAGS) -o $@
|
||||
|
||||
$(PACKAGE).bin: $(TARGET)
|
||||
$(QUIET) echo " OBJCOPY $@"
|
||||
$(QUIET) $(OBJCOPY) -O binary $(TARGET) $@
|
||||
|
||||
$(PACKAGE).dfu: $(TARGET)
|
||||
$(QUIET) echo " DFU $@"
|
||||
$(QUIET) $(COPY) $(PACKAGE).bin $@
|
||||
$(QUIET) dfu-suffix -v 1209 -p 70b1 -a $@
|
||||
|
||||
$(PACKAGE).ihex: $(TARGET)
|
||||
$(QUIET) echo " IHEX $(PACKAGE).ihex"
|
||||
$(QUIET) $(OBJCOPY) -O ihex $(TARGET) $@
|
||||
|
||||
$(DEBUG): CFLAGS += $(DBG_CFLAGS)
|
||||
$(DEBUG): LFLAGS += $(DBG_LFLAGS)
|
||||
CFLAGS += $(DBG_CFLAGS)
|
||||
LFLAGS += $(DBG_LFLAGS)
|
||||
$(DEBUG): $(TARGET)
|
||||
|
||||
$(OBJ_DIR):
|
||||
$(QUIET) mkdir $(OBJ_DIR)
|
||||
|
||||
$(COBJS) : $(OBJ_DIR)/%.o : %.c $(BASE_DIR)/Makefile
|
||||
$(QUIET) echo " CC $< $(notdir $@)"
|
||||
$(QUIET) $(CC) -c $< $(CFLAGS) -o $@ -MMD
|
||||
|
||||
$(OBJ_DIR)/%.o: %.cpp
|
||||
$(QUIET) echo " CXX $< $(notdir $@)"
|
||||
$(QUIET) $(CXX) -c $< $(CXXFLAGS) -o $@ -MMD
|
||||
|
||||
$(OBJ_DIR)/%.o: %.S
|
||||
$(QUIET) echo " AS $< $(notdir $@)"
|
||||
$(QUIET) $(CC) -x assembler-with-cpp -c $< $(CFLAGS) -o $@ -MMD
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
clean:
|
||||
$(QUIET) echo " RM $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.d))"
|
||||
-$(QUIET) $(RM) $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.d))
|
||||
$(QUIET) echo " RM $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.d))"
|
||||
-$(QUIET) $(RM) $(subst /,$(PATH_SEP),$(wildcard $(OBJ_DIR)/*.o))
|
||||
$(QUIET) echo " RM $(TARGET) $(PACKAGE).bin $(PACKAGE).symbol $(PACKAGE).ihex $(PACKAGE).dfu"
|
||||
-$(QUIET) $(RM) $(TARGET) $(PACKAGE).bin $(PACKAGE).symbol $(PACKAGE).ihex $(PACKAGE).dfu
|
||||
|
||||
include $(wildcard $(OBJ_DIR)/*.d)
|
903
sw/include/fomu/csr.h
Normal file
903
sw/include/fomu/csr.h
Normal file
@ -0,0 +1,903 @@
|
||||
#ifndef __GENERATED_CSR_H
|
||||
#define __GENERATED_CSR_H
|
||||
#include <stdint.h>
|
||||
#ifdef CSR_ACCESSORS_DEFINED
|
||||
extern void csr_writeb(uint8_t value, uint32_t addr);
|
||||
extern uint8_t csr_readb(uint32_t addr);
|
||||
extern void csr_writew(uint16_t value, uint32_t addr);
|
||||
extern uint16_t csr_readw(uint32_t addr);
|
||||
extern void csr_writel(uint32_t value, uint32_t addr);
|
||||
extern uint32_t csr_readl(uint32_t addr);
|
||||
#else /* ! CSR_ACCESSORS_DEFINED */
|
||||
static inline void csr_writeb(uint8_t value, uint32_t addr)
|
||||
{
|
||||
*((volatile uint8_t *)addr) = value;
|
||||
}
|
||||
|
||||
static inline uint8_t csr_readb(uint32_t addr)
|
||||
{
|
||||
return *(volatile uint8_t *)addr;
|
||||
}
|
||||
|
||||
static inline void csr_writew(uint16_t value, uint32_t addr)
|
||||
{
|
||||
*((volatile uint16_t *)addr) = value;
|
||||
}
|
||||
|
||||
static inline uint16_t csr_readw(uint32_t addr)
|
||||
{
|
||||
return *(volatile uint16_t *)addr;
|
||||
}
|
||||
|
||||
static inline void csr_writel(uint32_t value, uint32_t addr)
|
||||
{
|
||||
*((volatile uint32_t *)addr) = value;
|
||||
}
|
||||
|
||||
static inline uint32_t csr_readl(uint32_t addr)
|
||||
{
|
||||
return *(volatile uint32_t *)addr;
|
||||
}
|
||||
#endif /* ! CSR_ACCESSORS_DEFINED */
|
||||
|
||||
/* ctrl */
|
||||
#define CSR_CTRL_BASE 0xe0000000
|
||||
#define CSR_CTRL_RESET_ADDR 0xe0000000
|
||||
#define CSR_CTRL_RESET_SIZE 1
|
||||
static inline unsigned char
|
||||
ctrl_reset_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0000000);
|
||||
return r;
|
||||
}
|
||||
static inline void ctrl_reset_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0000000);
|
||||
}
|
||||
#define CSR_CTRL_SCRATCH_ADDR 0xe0000004
|
||||
#define CSR_CTRL_SCRATCH_SIZE 4
|
||||
static inline unsigned int ctrl_scratch_read(void)
|
||||
{
|
||||
unsigned int r = csr_readl(0xe0000004);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0000008);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe000000c);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0000010);
|
||||
return r;
|
||||
}
|
||||
static inline void ctrl_scratch_write(unsigned int value)
|
||||
{
|
||||
csr_writel(value >> 24, 0xe0000004);
|
||||
csr_writel(value >> 16, 0xe0000008);
|
||||
csr_writel(value >> 8, 0xe000000c);
|
||||
csr_writel(value, 0xe0000010);
|
||||
}
|
||||
#define CSR_CTRL_BUS_ERRORS_ADDR 0xe0000014
|
||||
#define CSR_CTRL_BUS_ERRORS_SIZE 4
|
||||
static inline unsigned int ctrl_bus_errors_read(void)
|
||||
{
|
||||
unsigned int r = csr_readl(0xe0000014);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0000018);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe000001c);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0000020);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* picorvspi */
|
||||
#define CSR_PICORVSPI_BASE 0xe0005000
|
||||
#define CSR_PICORVSPI_CFG1_ADDR 0xe0005000
|
||||
#define CSR_PICORVSPI_CFG1_SIZE 1
|
||||
static inline unsigned char picorvspi_cfg1_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0005000);
|
||||
return r;
|
||||
}
|
||||
static inline void picorvspi_cfg1_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0005000);
|
||||
}
|
||||
#define CSR_PICORVSPI_CFG2_ADDR 0xe0005004
|
||||
#define CSR_PICORVSPI_CFG2_SIZE 1
|
||||
static inline unsigned char picorvspi_cfg2_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0005004);
|
||||
return r;
|
||||
}
|
||||
static inline void picorvspi_cfg2_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0005004);
|
||||
}
|
||||
#define CSR_PICORVSPI_CFG3_ADDR 0xe0005008
|
||||
#define CSR_PICORVSPI_CFG3_SIZE 1
|
||||
static inline unsigned char picorvspi_cfg3_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0005008);
|
||||
return r;
|
||||
}
|
||||
static inline void picorvspi_cfg3_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0005008);
|
||||
}
|
||||
#define CSR_PICORVSPI_CFG4_ADDR 0xe000500c
|
||||
#define CSR_PICORVSPI_CFG4_SIZE 1
|
||||
static inline unsigned char picorvspi_cfg4_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe000500c);
|
||||
return r;
|
||||
}
|
||||
static inline void picorvspi_cfg4_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe000500c);
|
||||
}
|
||||
#define CSR_PICORVSPI_STAT1_ADDR 0xe0005010
|
||||
#define CSR_PICORVSPI_STAT1_SIZE 1
|
||||
static inline unsigned char picorvspi_stat1_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0005010);
|
||||
return r;
|
||||
}
|
||||
#define CSR_PICORVSPI_STAT2_ADDR 0xe0005014
|
||||
#define CSR_PICORVSPI_STAT2_SIZE 1
|
||||
static inline unsigned char picorvspi_stat2_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0005014);
|
||||
return r;
|
||||
}
|
||||
#define CSR_PICORVSPI_STAT3_ADDR 0xe0005018
|
||||
#define CSR_PICORVSPI_STAT3_SIZE 1
|
||||
static inline unsigned char picorvspi_stat3_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0005018);
|
||||
return r;
|
||||
}
|
||||
#define CSR_PICORVSPI_STAT4_ADDR 0xe000501c
|
||||
#define CSR_PICORVSPI_STAT4_SIZE 1
|
||||
static inline unsigned char picorvspi_stat4_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe000501c);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* reboot */
|
||||
#define CSR_REBOOT_BASE 0xe0006000
|
||||
#define CSR_REBOOT_CTRL_ADDR 0xe0006000
|
||||
#define CSR_REBOOT_CTRL_SIZE 1
|
||||
static inline unsigned char reboot_ctrl_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0006000);
|
||||
return r;
|
||||
}
|
||||
static inline void reboot_ctrl_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0006000);
|
||||
}
|
||||
#define CSR_REBOOT_ADDR_ADDR 0xe0006004
|
||||
#define CSR_REBOOT_ADDR_SIZE 4
|
||||
static inline unsigned int reboot_addr_read(void)
|
||||
{
|
||||
unsigned int r = csr_readl(0xe0006004);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0006008);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe000600c);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0006010);
|
||||
return r;
|
||||
}
|
||||
static inline void reboot_addr_write(unsigned int value)
|
||||
{
|
||||
csr_writel(value >> 24, 0xe0006004);
|
||||
csr_writel(value >> 16, 0xe0006008);
|
||||
csr_writel(value >> 8, 0xe000600c);
|
||||
csr_writel(value, 0xe0006010);
|
||||
}
|
||||
|
||||
/* rgb */
|
||||
#define CSR_RGB_BASE 0xe0006800
|
||||
#define CSR_RGB_DAT_ADDR 0xe0006800
|
||||
#define CSR_RGB_DAT_SIZE 1
|
||||
static inline unsigned char rgb_dat_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0006800);
|
||||
return r;
|
||||
}
|
||||
static inline void rgb_dat_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0006800);
|
||||
}
|
||||
#define CSR_RGB_ADDR_ADDR 0xe0006804
|
||||
#define CSR_RGB_ADDR_SIZE 1
|
||||
static inline unsigned char rgb_addr_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0006804);
|
||||
return r;
|
||||
}
|
||||
static inline void rgb_addr_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0006804);
|
||||
}
|
||||
#define CSR_RGB_CTRL_ADDR 0xe0006808
|
||||
#define CSR_RGB_CTRL_SIZE 1
|
||||
static inline unsigned char rgb_ctrl_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0006808);
|
||||
return r;
|
||||
}
|
||||
static inline void rgb_ctrl_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0006808);
|
||||
}
|
||||
|
||||
/* timer0 */
|
||||
#define CSR_TIMER0_BASE 0xe0002800
|
||||
#define CSR_TIMER0_LOAD_ADDR 0xe0002800
|
||||
#define CSR_TIMER0_LOAD_SIZE 4
|
||||
static inline unsigned int timer0_load_read(void)
|
||||
{
|
||||
unsigned int r = csr_readl(0xe0002800);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0002804);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0002808);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe000280c);
|
||||
return r;
|
||||
}
|
||||
static inline void timer0_load_write(unsigned int value)
|
||||
{
|
||||
csr_writel(value >> 24, 0xe0002800);
|
||||
csr_writel(value >> 16, 0xe0002804);
|
||||
csr_writel(value >> 8, 0xe0002808);
|
||||
csr_writel(value, 0xe000280c);
|
||||
}
|
||||
#define CSR_TIMER0_RELOAD_ADDR 0xe0002810
|
||||
#define CSR_TIMER0_RELOAD_SIZE 4
|
||||
static inline unsigned int timer0_reload_read(void)
|
||||
{
|
||||
unsigned int r = csr_readl(0xe0002810);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0002814);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0002818);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe000281c);
|
||||
return r;
|
||||
}
|
||||
static inline void timer0_reload_write(unsigned int value)
|
||||
{
|
||||
csr_writel(value >> 24, 0xe0002810);
|
||||
csr_writel(value >> 16, 0xe0002814);
|
||||
csr_writel(value >> 8, 0xe0002818);
|
||||
csr_writel(value, 0xe000281c);
|
||||
}
|
||||
#define CSR_TIMER0_EN_ADDR 0xe0002820
|
||||
#define CSR_TIMER0_EN_SIZE 1
|
||||
static inline unsigned char timer0_en_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0002820);
|
||||
return r;
|
||||
}
|
||||
static inline void timer0_en_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0002820);
|
||||
}
|
||||
#define CSR_TIMER0_UPDATE_VALUE_ADDR 0xe0002824
|
||||
#define CSR_TIMER0_UPDATE_VALUE_SIZE 1
|
||||
static inline unsigned char timer0_update_value_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0002824);
|
||||
return r;
|
||||
}
|
||||
static inline void timer0_update_value_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0002824);
|
||||
}
|
||||
#define CSR_TIMER0_VALUE_ADDR 0xe0002828
|
||||
#define CSR_TIMER0_VALUE_SIZE 4
|
||||
static inline unsigned int timer0_value_read(void)
|
||||
{
|
||||
unsigned int r = csr_readl(0xe0002828);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe000282c);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0002830);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0002834);
|
||||
return r;
|
||||
}
|
||||
#define CSR_TIMER0_EV_STATUS_ADDR 0xe0002838
|
||||
#define CSR_TIMER0_EV_STATUS_SIZE 1
|
||||
static inline unsigned char timer0_ev_status_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0002838);
|
||||
return r;
|
||||
}
|
||||
static inline void timer0_ev_status_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0002838);
|
||||
}
|
||||
#define CSR_TIMER0_EV_PENDING_ADDR 0xe000283c
|
||||
#define CSR_TIMER0_EV_PENDING_SIZE 1
|
||||
static inline unsigned char timer0_ev_pending_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe000283c);
|
||||
return r;
|
||||
}
|
||||
static inline void timer0_ev_pending_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe000283c);
|
||||
}
|
||||
#define CSR_TIMER0_EV_ENABLE_ADDR 0xe0002840
|
||||
#define CSR_TIMER0_EV_ENABLE_SIZE 1
|
||||
static inline unsigned char timer0_ev_enable_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0002840);
|
||||
return r;
|
||||
}
|
||||
static inline void timer0_ev_enable_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0002840);
|
||||
}
|
||||
|
||||
/* touch */
|
||||
#define CSR_TOUCH_BASE 0xe0005800
|
||||
#define CSR_TOUCH_O_ADDR 0xe0005800
|
||||
#define CSR_TOUCH_O_SIZE 1
|
||||
static inline unsigned char touch_o_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0005800);
|
||||
return r;
|
||||
}
|
||||
static inline void touch_o_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0005800);
|
||||
}
|
||||
#define CSR_TOUCH_OE_ADDR 0xe0005804
|
||||
#define CSR_TOUCH_OE_SIZE 1
|
||||
static inline unsigned char touch_oe_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0005804);
|
||||
return r;
|
||||
}
|
||||
static inline void touch_oe_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0005804);
|
||||
}
|
||||
#define CSR_TOUCH_I_ADDR 0xe0005808
|
||||
#define CSR_TOUCH_I_SIZE 1
|
||||
static inline unsigned char touch_i_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0005808);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* usb */
|
||||
#define CSR_USB_BASE 0xe0004800
|
||||
#define CSR_USB_PULLUP_OUT_ADDR 0xe0004800
|
||||
#define CSR_USB_PULLUP_OUT_SIZE 1
|
||||
static inline unsigned char usb_pullup_out_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004800);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_pullup_out_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004800);
|
||||
}
|
||||
#define CSR_USB_EP_0_OUT_EV_STATUS_ADDR 0xe0004804
|
||||
#define CSR_USB_EP_0_OUT_EV_STATUS_SIZE 1
|
||||
static inline unsigned char usb_ep_0_out_ev_status_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004804);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_out_ev_status_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004804);
|
||||
}
|
||||
#define CSR_USB_EP_0_OUT_EV_PENDING_ADDR 0xe0004808
|
||||
#define CSR_USB_EP_0_OUT_EV_PENDING_SIZE 1
|
||||
static inline unsigned char usb_ep_0_out_ev_pending_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004808);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_out_ev_pending_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004808);
|
||||
}
|
||||
#define CSR_USB_EP_0_OUT_EV_ENABLE_ADDR 0xe000480c
|
||||
#define CSR_USB_EP_0_OUT_EV_ENABLE_SIZE 1
|
||||
static inline unsigned char usb_ep_0_out_ev_enable_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe000480c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_out_ev_enable_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe000480c);
|
||||
}
|
||||
#define CSR_USB_EP_0_OUT_LAST_TOK_ADDR 0xe0004810
|
||||
#define CSR_USB_EP_0_OUT_LAST_TOK_SIZE 1
|
||||
static inline unsigned char usb_ep_0_out_last_tok_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004810);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_EP_0_OUT_RESPOND_ADDR 0xe0004814
|
||||
#define CSR_USB_EP_0_OUT_RESPOND_SIZE 1
|
||||
static inline unsigned char usb_ep_0_out_respond_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004814);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_out_respond_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004814);
|
||||
}
|
||||
#define CSR_USB_EP_0_OUT_DTB_ADDR 0xe0004818
|
||||
#define CSR_USB_EP_0_OUT_DTB_SIZE 1
|
||||
static inline unsigned char usb_ep_0_out_dtb_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004818);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_out_dtb_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004818);
|
||||
}
|
||||
#define CSR_USB_EP_0_OUT_OBUF_HEAD_ADDR 0xe000481c
|
||||
#define CSR_USB_EP_0_OUT_OBUF_HEAD_SIZE 1
|
||||
static inline unsigned char usb_ep_0_out_obuf_head_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe000481c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_out_obuf_head_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe000481c);
|
||||
}
|
||||
#define CSR_USB_EP_0_OUT_OBUF_EMPTY_ADDR 0xe0004820
|
||||
#define CSR_USB_EP_0_OUT_OBUF_EMPTY_SIZE 1
|
||||
static inline unsigned char usb_ep_0_out_obuf_empty_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004820);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_EP_0_IN_EV_STATUS_ADDR 0xe0004824
|
||||
#define CSR_USB_EP_0_IN_EV_STATUS_SIZE 1
|
||||
static inline unsigned char usb_ep_0_in_ev_status_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004824);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_in_ev_status_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004824);
|
||||
}
|
||||
#define CSR_USB_EP_0_IN_EV_PENDING_ADDR 0xe0004828
|
||||
#define CSR_USB_EP_0_IN_EV_PENDING_SIZE 1
|
||||
static inline unsigned char usb_ep_0_in_ev_pending_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004828);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_in_ev_pending_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004828);
|
||||
}
|
||||
#define CSR_USB_EP_0_IN_EV_ENABLE_ADDR 0xe000482c
|
||||
#define CSR_USB_EP_0_IN_EV_ENABLE_SIZE 1
|
||||
static inline unsigned char usb_ep_0_in_ev_enable_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe000482c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_in_ev_enable_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe000482c);
|
||||
}
|
||||
#define CSR_USB_EP_0_IN_LAST_TOK_ADDR 0xe0004830
|
||||
#define CSR_USB_EP_0_IN_LAST_TOK_SIZE 1
|
||||
static inline unsigned char usb_ep_0_in_last_tok_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004830);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_EP_0_IN_RESPOND_ADDR 0xe0004834
|
||||
#define CSR_USB_EP_0_IN_RESPOND_SIZE 1
|
||||
static inline unsigned char usb_ep_0_in_respond_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004834);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_in_respond_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004834);
|
||||
}
|
||||
#define CSR_USB_EP_0_IN_DTB_ADDR 0xe0004838
|
||||
#define CSR_USB_EP_0_IN_DTB_SIZE 1
|
||||
static inline unsigned char usb_ep_0_in_dtb_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004838);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_in_dtb_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004838);
|
||||
}
|
||||
#define CSR_USB_EP_0_IN_IBUF_HEAD_ADDR 0xe000483c
|
||||
#define CSR_USB_EP_0_IN_IBUF_HEAD_SIZE 1
|
||||
static inline unsigned char usb_ep_0_in_ibuf_head_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe000483c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_0_in_ibuf_head_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe000483c);
|
||||
}
|
||||
#define CSR_USB_EP_0_IN_IBUF_EMPTY_ADDR 0xe0004840
|
||||
#define CSR_USB_EP_0_IN_IBUF_EMPTY_SIZE 1
|
||||
static inline unsigned char usb_ep_0_in_ibuf_empty_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004840);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_EP_1_IN_EV_STATUS_ADDR 0xe0004844
|
||||
#define CSR_USB_EP_1_IN_EV_STATUS_SIZE 1
|
||||
static inline unsigned char usb_ep_1_in_ev_status_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004844);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_1_in_ev_status_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004844);
|
||||
}
|
||||
#define CSR_USB_EP_1_IN_EV_PENDING_ADDR 0xe0004848
|
||||
#define CSR_USB_EP_1_IN_EV_PENDING_SIZE 1
|
||||
static inline unsigned char usb_ep_1_in_ev_pending_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004848);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_1_in_ev_pending_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004848);
|
||||
}
|
||||
#define CSR_USB_EP_1_IN_EV_ENABLE_ADDR 0xe000484c
|
||||
#define CSR_USB_EP_1_IN_EV_ENABLE_SIZE 1
|
||||
static inline unsigned char usb_ep_1_in_ev_enable_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe000484c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_1_in_ev_enable_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe000484c);
|
||||
}
|
||||
#define CSR_USB_EP_1_IN_LAST_TOK_ADDR 0xe0004850
|
||||
#define CSR_USB_EP_1_IN_LAST_TOK_SIZE 1
|
||||
static inline unsigned char usb_ep_1_in_last_tok_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004850);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_EP_1_IN_RESPOND_ADDR 0xe0004854
|
||||
#define CSR_USB_EP_1_IN_RESPOND_SIZE 1
|
||||
static inline unsigned char usb_ep_1_in_respond_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004854);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_1_in_respond_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004854);
|
||||
}
|
||||
#define CSR_USB_EP_1_IN_DTB_ADDR 0xe0004858
|
||||
#define CSR_USB_EP_1_IN_DTB_SIZE 1
|
||||
static inline unsigned char usb_ep_1_in_dtb_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004858);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_1_in_dtb_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004858);
|
||||
}
|
||||
#define CSR_USB_EP_1_IN_IBUF_HEAD_ADDR 0xe000485c
|
||||
#define CSR_USB_EP_1_IN_IBUF_HEAD_SIZE 1
|
||||
static inline unsigned char usb_ep_1_in_ibuf_head_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe000485c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_1_in_ibuf_head_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe000485c);
|
||||
}
|
||||
#define CSR_USB_EP_1_IN_IBUF_EMPTY_ADDR 0xe0004860
|
||||
#define CSR_USB_EP_1_IN_IBUF_EMPTY_SIZE 1
|
||||
static inline unsigned char usb_ep_1_in_ibuf_empty_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004860);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_EP_2_OUT_EV_STATUS_ADDR 0xe0004864
|
||||
#define CSR_USB_EP_2_OUT_EV_STATUS_SIZE 1
|
||||
static inline unsigned char usb_ep_2_out_ev_status_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004864);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_out_ev_status_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004864);
|
||||
}
|
||||
#define CSR_USB_EP_2_OUT_EV_PENDING_ADDR 0xe0004868
|
||||
#define CSR_USB_EP_2_OUT_EV_PENDING_SIZE 1
|
||||
static inline unsigned char usb_ep_2_out_ev_pending_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004868);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_out_ev_pending_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004868);
|
||||
}
|
||||
#define CSR_USB_EP_2_OUT_EV_ENABLE_ADDR 0xe000486c
|
||||
#define CSR_USB_EP_2_OUT_EV_ENABLE_SIZE 1
|
||||
static inline unsigned char usb_ep_2_out_ev_enable_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe000486c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_out_ev_enable_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe000486c);
|
||||
}
|
||||
#define CSR_USB_EP_2_OUT_LAST_TOK_ADDR 0xe0004870
|
||||
#define CSR_USB_EP_2_OUT_LAST_TOK_SIZE 1
|
||||
static inline unsigned char usb_ep_2_out_last_tok_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004870);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_EP_2_OUT_RESPOND_ADDR 0xe0004874
|
||||
#define CSR_USB_EP_2_OUT_RESPOND_SIZE 1
|
||||
static inline unsigned char usb_ep_2_out_respond_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004874);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_out_respond_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004874);
|
||||
}
|
||||
#define CSR_USB_EP_2_OUT_DTB_ADDR 0xe0004878
|
||||
#define CSR_USB_EP_2_OUT_DTB_SIZE 1
|
||||
static inline unsigned char usb_ep_2_out_dtb_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004878);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_out_dtb_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004878);
|
||||
}
|
||||
#define CSR_USB_EP_2_OUT_OBUF_HEAD_ADDR 0xe000487c
|
||||
#define CSR_USB_EP_2_OUT_OBUF_HEAD_SIZE 1
|
||||
static inline unsigned char usb_ep_2_out_obuf_head_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe000487c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_out_obuf_head_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe000487c);
|
||||
}
|
||||
#define CSR_USB_EP_2_OUT_OBUF_EMPTY_ADDR 0xe0004880
|
||||
#define CSR_USB_EP_2_OUT_OBUF_EMPTY_SIZE 1
|
||||
static inline unsigned char usb_ep_2_out_obuf_empty_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004880);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_EP_2_IN_EV_STATUS_ADDR 0xe0004884
|
||||
#define CSR_USB_EP_2_IN_EV_STATUS_SIZE 1
|
||||
static inline unsigned char usb_ep_2_in_ev_status_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004884);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_in_ev_status_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004884);
|
||||
}
|
||||
#define CSR_USB_EP_2_IN_EV_PENDING_ADDR 0xe0004888
|
||||
#define CSR_USB_EP_2_IN_EV_PENDING_SIZE 1
|
||||
static inline unsigned char usb_ep_2_in_ev_pending_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004888);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_in_ev_pending_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004888);
|
||||
}
|
||||
#define CSR_USB_EP_2_IN_EV_ENABLE_ADDR 0xe000488c
|
||||
#define CSR_USB_EP_2_IN_EV_ENABLE_SIZE 1
|
||||
static inline unsigned char usb_ep_2_in_ev_enable_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe000488c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_in_ev_enable_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe000488c);
|
||||
}
|
||||
#define CSR_USB_EP_2_IN_LAST_TOK_ADDR 0xe0004890
|
||||
#define CSR_USB_EP_2_IN_LAST_TOK_SIZE 1
|
||||
static inline unsigned char usb_ep_2_in_last_tok_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004890);
|
||||
return r;
|
||||
}
|
||||
#define CSR_USB_EP_2_IN_RESPOND_ADDR 0xe0004894
|
||||
#define CSR_USB_EP_2_IN_RESPOND_SIZE 1
|
||||
static inline unsigned char usb_ep_2_in_respond_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004894);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_in_respond_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004894);
|
||||
}
|
||||
#define CSR_USB_EP_2_IN_DTB_ADDR 0xe0004898
|
||||
#define CSR_USB_EP_2_IN_DTB_SIZE 1
|
||||
static inline unsigned char usb_ep_2_in_dtb_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0004898);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_in_dtb_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe0004898);
|
||||
}
|
||||
#define CSR_USB_EP_2_IN_IBUF_HEAD_ADDR 0xe000489c
|
||||
#define CSR_USB_EP_2_IN_IBUF_HEAD_SIZE 1
|
||||
static inline unsigned char usb_ep_2_in_ibuf_head_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe000489c);
|
||||
return r;
|
||||
}
|
||||
static inline void usb_ep_2_in_ibuf_head_write(unsigned char value)
|
||||
{
|
||||
csr_writel(value, 0xe000489c);
|
||||
}
|
||||
#define CSR_USB_EP_2_IN_IBUF_EMPTY_ADDR 0xe00048a0
|
||||
#define CSR_USB_EP_2_IN_IBUF_EMPTY_SIZE 1
|
||||
static inline unsigned char usb_ep_2_in_ibuf_empty_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe00048a0);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* version */
|
||||
#define CSR_VERSION_BASE 0xe0007000
|
||||
#define CSR_VERSION_MAJOR_ADDR 0xe0007000
|
||||
#define CSR_VERSION_MAJOR_SIZE 1
|
||||
static inline unsigned char version_major_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0007000);
|
||||
return r;
|
||||
}
|
||||
#define CSR_VERSION_MINOR_ADDR 0xe0007004
|
||||
#define CSR_VERSION_MINOR_SIZE 1
|
||||
static inline unsigned char version_minor_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0007004);
|
||||
return r;
|
||||
}
|
||||
#define CSR_VERSION_REVISION_ADDR 0xe0007008
|
||||
#define CSR_VERSION_REVISION_SIZE 1
|
||||
static inline unsigned char version_revision_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0007008);
|
||||
return r;
|
||||
}
|
||||
#define CSR_VERSION_GITREV_ADDR 0xe000700c
|
||||
#define CSR_VERSION_GITREV_SIZE 4
|
||||
static inline unsigned int version_gitrev_read(void)
|
||||
{
|
||||
unsigned int r = csr_readl(0xe000700c);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0007010);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0007014);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0007018);
|
||||
return r;
|
||||
}
|
||||
#define CSR_VERSION_GITEXTRA_ADDR 0xe000701c
|
||||
#define CSR_VERSION_GITEXTRA_SIZE 2
|
||||
static inline unsigned short int version_gitextra_read(void)
|
||||
{
|
||||
unsigned short int r = csr_readl(0xe000701c);
|
||||
r <<= 8;
|
||||
r |= csr_readl(0xe0007020);
|
||||
return r;
|
||||
}
|
||||
#define CSR_VERSION_DIRTY_ADDR 0xe0007024
|
||||
#define CSR_VERSION_DIRTY_SIZE 1
|
||||
static inline unsigned char version_dirty_read(void)
|
||||
{
|
||||
unsigned char r = csr_readl(0xe0007024);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* constants */
|
||||
#define NMI_INTERRUPT 0
|
||||
static inline int nmi_interrupt_read(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#define TIMER0_INTERRUPT 1
|
||||
static inline int timer0_interrupt_read(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#define UART_INTERRUPT 2
|
||||
static inline int uart_interrupt_read(void)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
#define USB_INTERRUPT 3
|
||||
static inline int usb_interrupt_read(void)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
#define CSR_DATA_WIDTH 8
|
||||
static inline int csr_data_width_read(void)
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
#define SYSTEM_CLOCK_FREQUENCY 12000000
|
||||
static inline int system_clock_frequency_read(void)
|
||||
{
|
||||
return 12000000;
|
||||
}
|
||||
#define CONFIG_CLOCK_FREQUENCY 12000000
|
||||
static inline int config_clock_frequency_read(void)
|
||||
{
|
||||
return 12000000;
|
||||
}
|
||||
#define CONFIG_CPU_RESET_ADDR 0
|
||||
static inline int config_cpu_reset_addr_read(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#define CONFIG_CPU_TYPE "VEXRISCV"
|
||||
static inline const char *config_cpu_type_read(void)
|
||||
{
|
||||
return "VEXRISCV";
|
||||
}
|
||||
#define CONFIG_CPU_VARIANT "VEXRISCV"
|
||||
static inline const char *config_cpu_variant_read(void)
|
||||
{
|
||||
return "VEXRISCV";
|
||||
}
|
||||
#define CONFIG_CSR_DATA_WIDTH 8
|
||||
static inline int config_csr_data_width_read(void)
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
#endif
|
16
sw/include/fomu/mem.h
Normal file
16
sw/include/fomu/mem.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __GENERATED_MEM_H
|
||||
#define __GENERATED_MEM_H
|
||||
|
||||
#define VEXRISCV_DEBUG_BASE 0xf00f0000
|
||||
#define VEXRISCV_DEBUG_SIZE 0x00000010
|
||||
|
||||
#define SRAM_BASE 0x10000000
|
||||
#define SRAM_SIZE 0x00020000
|
||||
|
||||
#define ROM_BASE 0x00000000
|
||||
#define ROM_SIZE 0x00002000
|
||||
|
||||
#define SPIFLASH_BASE 0x20000000
|
||||
#define SPIFLASH_SIZE 0x00200000
|
||||
|
||||
#endif
|
145
sw/include/irq.h
Normal file
145
sw/include/irq.h
Normal file
@ -0,0 +1,145 @@
|
||||
#ifndef __IRQ_H
|
||||
#define __IRQ_H
|
||||
|
||||
#include <riscv.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __picorv32__
|
||||
// PicoRV32 has a very limited interrupt support, implemented via custom
|
||||
// instructions. It also doesn't have a global interrupt enable/disable, so
|
||||
// we have to emulate it via saving and restoring a mask and using 0/~1 as a
|
||||
// hardware mask.
|
||||
// Due to all this somewhat low-level mess, all of the glue is implemented in
|
||||
// the RiscV crt0, and this header is kept as a thin wrapper. Since interrupts
|
||||
// managed by this layer, do not call interrupt instructions directly, as the
|
||||
// state will go out of sync with the hardware.
|
||||
|
||||
// Read only.
|
||||
extern unsigned int _irq_pending;
|
||||
// Read only.
|
||||
extern unsigned int _irq_mask;
|
||||
// Read only.
|
||||
extern unsigned int _irq_enabled;
|
||||
extern void _irq_enable(void);
|
||||
extern void _irq_disable(void);
|
||||
extern void _irq_setmask(unsigned int);
|
||||
#endif
|
||||
|
||||
static inline unsigned int irq_getie(void)
|
||||
{
|
||||
#if defined (__lm32__)
|
||||
unsigned int ie;
|
||||
__asm__ __volatile__("rcsr %0, IE" : "=r" (ie));
|
||||
return ie;
|
||||
#elif defined (__or1k__)
|
||||
return !!(mfspr(SPR_SR) & SPR_SR_IEE);
|
||||
#elif defined (__picorv32__)
|
||||
return _irq_enabled != 0;
|
||||
#elif defined (__vexriscv__)
|
||||
return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0;
|
||||
#elif defined (__minerva__)
|
||||
return (csrr(mstatus) & CSR_MSTATUS_MIE) != 0;
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void irq_setie(unsigned int ie)
|
||||
{
|
||||
#if defined (__lm32__)
|
||||
__asm__ __volatile__("wcsr IE, %0" : : "r" (ie));
|
||||
#elif defined (__or1k__)
|
||||
if (ie & 0x1)
|
||||
mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_IEE);
|
||||
else
|
||||
mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_IEE);
|
||||
#elif defined (__picorv32__)
|
||||
if (ie & 0x1)
|
||||
_irq_enable();
|
||||
else
|
||||
_irq_disable();
|
||||
#elif defined (__vexriscv__)
|
||||
if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE);
|
||||
#elif defined (__minerva__)
|
||||
if(ie) csrs(mstatus,CSR_MSTATUS_MIE); else csrc(mstatus,CSR_MSTATUS_MIE);
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline unsigned int irq_getmask(void)
|
||||
{
|
||||
#if defined (__lm32__)
|
||||
unsigned int mask;
|
||||
__asm__ __volatile__("rcsr %0, IM" : "=r" (mask));
|
||||
return mask;
|
||||
#elif defined (__or1k__)
|
||||
return mfspr(SPR_PICMR);
|
||||
#elif defined (__picorv32__)
|
||||
// PicoRV32 interrupt mask bits are high-disabled. This is the inverse of how
|
||||
// LiteX sees things.
|
||||
return ~_irq_mask;
|
||||
#elif defined (__vexriscv__)
|
||||
unsigned int mask;
|
||||
asm volatile ("csrr %0, %1" : "=r"(mask) : "i"(CSR_IRQ_MASK));
|
||||
return mask;
|
||||
#elif defined (__minerva__)
|
||||
unsigned int mask;
|
||||
asm volatile ("csrr %0, %1" : "=r"(mask) : "i"(CSR_IRQ_MASK));
|
||||
return mask;
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void irq_setmask(unsigned int mask)
|
||||
{
|
||||
#if defined (__lm32__)
|
||||
__asm__ __volatile__("wcsr IM, %0" : : "r" (mask));
|
||||
#elif defined (__or1k__)
|
||||
mtspr(SPR_PICMR, mask);
|
||||
#elif defined (__picorv32__)
|
||||
// PicoRV32 interrupt mask bits are high-disabled. This is the inverse of how
|
||||
// LiteX sees things.
|
||||
_irq_setmask(~mask);
|
||||
#elif defined (__vexriscv__)
|
||||
asm volatile ("csrw %0, %1" :: "i"(CSR_IRQ_MASK), "r"(mask));
|
||||
#elif defined (__minerva__)
|
||||
asm volatile ("csrw %0, %1" :: "i"(CSR_IRQ_MASK), "r"(mask));
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline unsigned int irq_pending(void)
|
||||
{
|
||||
#if defined (__lm32__)
|
||||
unsigned int pending;
|
||||
__asm__ __volatile__("rcsr %0, IP" : "=r" (pending));
|
||||
return pending;
|
||||
#elif defined (__or1k__)
|
||||
return mfspr(SPR_PICSR);
|
||||
#elif defined (__picorv32__)
|
||||
return _irq_pending;
|
||||
#elif defined (__vexriscv__)
|
||||
unsigned int pending;
|
||||
asm volatile ("csrr %0, %1" : "=r"(pending) : "i"(CSR_IRQ_PENDING));
|
||||
return pending;
|
||||
#elif defined (__minerva__)
|
||||
unsigned int pending;
|
||||
asm volatile ("csrr %0, %1" : "=r"(pending) : "i"(CSR_IRQ_PENDING));
|
||||
return pending;
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __IRQ_H */
|
10
sw/include/rgb.h
Normal file
10
sw/include/rgb.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef _RGB_H_
|
||||
#define _RGB_H_
|
||||
|
||||
void rgb_init(void);
|
||||
void rgb_mode_idle(void);
|
||||
void rgb_mode_done(void);
|
||||
void rgb_mode_writing(void);
|
||||
void rgb_mode_error(void);
|
||||
|
||||
#endif /* _RGB_H_ */
|
54
sw/include/riscv.h
Normal file
54
sw/include/riscv.h
Normal file
@ -0,0 +1,54 @@
|
||||
#ifndef RISCV_DEFS_H__
|
||||
#define RISCV_DEFS_H__
|
||||
|
||||
#include <fomu/csr.h>
|
||||
|
||||
#define CSR_MSTATUS_MIE 0x8
|
||||
|
||||
#define CSR_IRQ_MASK 0xBC0
|
||||
#define CSR_IRQ_PENDING 0xFC0
|
||||
|
||||
#define CSR_DCACHE_INFO 0xCC0
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void flush_cpu_icache(void);
|
||||
void flush_cpu_dcache(void);
|
||||
void flush_l2_cache(void);
|
||||
|
||||
#define csrr(reg) ({ unsigned long __tmp; \
|
||||
asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
|
||||
__tmp; })
|
||||
|
||||
#define csrw(reg, val) ({ \
|
||||
if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \
|
||||
asm volatile ("csrw " #reg ", %0" :: "i"(val)); \
|
||||
else \
|
||||
asm volatile ("csrw " #reg ", %0" :: "r"(val)); })
|
||||
|
||||
#define csrs(reg, bit) ({ \
|
||||
if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \
|
||||
asm volatile ("csrrs x0, " #reg ", %0" :: "i"(bit)); \
|
||||
else \
|
||||
asm volatile ("csrrs x0, " #reg ", %0" :: "r"(bit)); })
|
||||
|
||||
#define csrc(reg, bit) ({ \
|
||||
if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \
|
||||
asm volatile ("csrrc x0, " #reg ", %0" :: "i"(bit)); \
|
||||
else \
|
||||
asm volatile ("csrrc x0, " #reg ", %0" :: "r"(bit)); })
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
__attribute__((noreturn)) void reboot(void);
|
||||
|
||||
__attribute__((noreturn)) static inline void warmboot_to_image(uint8_t image_index) {
|
||||
reboot_ctrl_write(0xac | (image_index & 3) << 0);
|
||||
while (1);
|
||||
}
|
||||
|
||||
#endif /* RISCV_DEFS_H__ */
|
94
sw/include/spi.h
Normal file
94
sw/include/spi.h
Normal file
@ -0,0 +1,94 @@
|
||||
#ifndef BB_SPI_H_
|
||||
#define BB_SPI_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum spi_state {
|
||||
SS_UNCONFIGURED = 0,
|
||||
SS_SINGLE,
|
||||
SS_DUAL_RX,
|
||||
SS_DUAL_TX,
|
||||
SS_QUAD_RX,
|
||||
SS_QUAD_TX,
|
||||
SS_HARDWARE,
|
||||
};
|
||||
|
||||
enum spi_type {
|
||||
ST_UNCONFIGURED,
|
||||
ST_SINGLE,
|
||||
ST_DUAL,
|
||||
ST_QUAD,
|
||||
ST_QPI,
|
||||
};
|
||||
|
||||
enum spi_pin {
|
||||
SP_MOSI,
|
||||
SP_MISO,
|
||||
SP_HOLD,
|
||||
SP_WP,
|
||||
SP_CS,
|
||||
SP_CLK,
|
||||
SP_D0,
|
||||
SP_D1,
|
||||
SP_D2,
|
||||
SP_D3,
|
||||
};
|
||||
|
||||
struct spi_id {
|
||||
uint8_t manufacturer_id; // Result from 0x90
|
||||
uint8_t device_id; // Result from 0x90
|
||||
uint8_t _manufacturer_id; // Result from 0x9f
|
||||
uint8_t memory_type; // Result from 0x9f
|
||||
uint8_t memory_size; // Result from 0x9f
|
||||
uint8_t signature; // Result from 0xab
|
||||
uint8_t serial[4]; // Result from 0x4b
|
||||
int bytes; // -1 if unknown
|
||||
const char *manufacturer;
|
||||
const char *model;
|
||||
const char *capacity;
|
||||
};
|
||||
|
||||
struct ff_spi;
|
||||
|
||||
void spiPause(struct ff_spi *spi);
|
||||
void spiBegin(struct ff_spi *spi);
|
||||
void spiEnd(struct ff_spi *spi);
|
||||
|
||||
//void spiSingleTx(struct ff_spi *spi, uint8_t out);
|
||||
//uint8_t spiSingleRx(struct ff_spi *spi);
|
||||
//void spiDualTx(struct ff_spi *spi, uint8_t out);
|
||||
//void spiQuadTx(struct ff_spi *spi, uint8_t out);
|
||||
void spiCommand(struct ff_spi *spi, uint8_t cmd);
|
||||
//uint8_t spiDualRx(struct ff_spi *spi);
|
||||
//uint8_t spiQuadRx(struct ff_spi *spi);
|
||||
int spiTx(struct ff_spi *spi, uint8_t word);
|
||||
uint8_t spiRx(struct ff_spi *spi);
|
||||
uint8_t spiReadStatus(struct ff_spi *spi, uint8_t sr);
|
||||
void spiWriteStatus(struct ff_spi *spi, uint8_t sr, uint8_t val);
|
||||
void spiReadSecurity(struct ff_spi *spi, uint8_t sr, uint8_t security[256]);
|
||||
void spiWriteSecurity(struct ff_spi *spi, uint8_t sr, uint8_t security[256]);
|
||||
int spiSetType(struct ff_spi *spi, enum spi_type type);
|
||||
int spiRead(struct ff_spi *spi, uint32_t addr, uint8_t *data, unsigned int count);
|
||||
int spiIsBusy(struct ff_spi *spi);
|
||||
int spiBeginErase32(struct ff_spi *spi, uint32_t erase_addr);
|
||||
int spiBeginErase64(struct ff_spi *spi, uint32_t erase_addr);
|
||||
int spiBeginWrite(struct ff_spi *spi, uint32_t addr, const void *data, unsigned int count);
|
||||
void spiEnableQuad(void);
|
||||
|
||||
struct spi_id spiId(struct ff_spi *spi);
|
||||
void spiOverrideSize(struct ff_spi *spi, uint32_t new_size);
|
||||
|
||||
//int spi_wait_for_not_busy(struct ff_spi *spi);
|
||||
int spiWrite(struct ff_spi *spi, uint32_t addr, const uint8_t *data, unsigned int count);
|
||||
uint8_t spiReset(struct ff_spi *spi);
|
||||
int spiInit(struct ff_spi *spi);
|
||||
|
||||
void spiHold(struct ff_spi *spi);
|
||||
void spiUnhold(struct ff_spi *spi);
|
||||
void spiSwapTxRx(struct ff_spi *spi);
|
||||
|
||||
struct ff_spi *spiAlloc(void);
|
||||
void spiSetPin(struct ff_spi *spi, enum spi_pin pin, int val);
|
||||
void spiFree(void);
|
||||
|
||||
#endif /* BB_SPI_H_ */
|
16
sw/include/time.h
Normal file
16
sw/include/time.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __TIME_H
|
||||
#define __TIME_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void time_init(void);
|
||||
int elapsed(int *last_event, int period);
|
||||
void msleep(int ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TIME_H */
|
162
sw/include/usb-cdc.h
Normal file
162
sw/include/usb-cdc.h
Normal file
@ -0,0 +1,162 @@
|
||||
/** @defgroup usb_cdc_defines USB CDC Type Definitions
|
||||
|
||||
@brief <b>Defined Constants and Types for the USB CDC Type Definitions</b>
|
||||
|
||||
@ingroup USB_defines
|
||||
|
||||
@version 1.0.0
|
||||
|
||||
@author @htmlonly © @endhtmlonly 2010
|
||||
Gareth McMullin <gareth@blacksphere.co.nz>
|
||||
|
||||
@date 10 March 2013
|
||||
|
||||
LGPL License Terms @ref lgpl_license
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**@{*/
|
||||
|
||||
#ifndef __CDC_H
|
||||
#define __CDC_H
|
||||
|
||||
/* Definitions of Communications Device Class from
|
||||
* "Universal Serial Bus Class Definitions for Communications Devices
|
||||
* Revision 1.2"
|
||||
*/
|
||||
|
||||
/* Table 2: Communications Device Class Code */
|
||||
#define USB_CLASS_CDC 0x02
|
||||
|
||||
/* Table 4: Class Subclass Code */
|
||||
#define USB_CDC_SUBCLASS_DLCM 0x01
|
||||
#define USB_CDC_SUBCLASS_ACM 0x02
|
||||
/* ... */
|
||||
|
||||
/* Table 5 Communications Interface Class Control Protocol Codes */
|
||||
#define USB_CDC_PROTOCOL_NONE 0x00
|
||||
#define USB_CDC_PROTOCOL_AT 0x01
|
||||
/* ... */
|
||||
|
||||
/* Table 6: Data Interface Class Code */
|
||||
#define USB_CLASS_DATA 0x0A
|
||||
|
||||
/* Table 12: Type Values for the bDescriptorType Field */
|
||||
#define CS_INTERFACE 0x24
|
||||
#define CS_ENDPOINT 0x25
|
||||
|
||||
/* Table 13: bDescriptor SubType in Communications Class Functional
|
||||
* Descriptors */
|
||||
#define USB_CDC_TYPE_HEADER 0x00
|
||||
#define USB_CDC_TYPE_CALL_MANAGEMENT 0x01
|
||||
#define USB_CDC_TYPE_ACM 0x02
|
||||
/* ... */
|
||||
#define USB_CDC_TYPE_UNION 0x06
|
||||
/* ... */
|
||||
|
||||
/* Table 15: Class-Specific Descriptor Header Format */
|
||||
struct usb_cdc_header_descriptor {
|
||||
uint8_t bFunctionLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bDescriptorSubtype;
|
||||
uint16_t bcdCDC;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Table 16: Union Interface Functional Descriptor */
|
||||
struct usb_cdc_union_descriptor {
|
||||
uint8_t bFunctionLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bDescriptorSubtype;
|
||||
uint8_t bControlInterface;
|
||||
uint8_t bSubordinateInterface0;
|
||||
/* ... */
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/* Definitions for Abstract Control Model devices from:
|
||||
* "Universal Serial Bus Communications Class Subclass Specification for
|
||||
* PSTN Devices"
|
||||
*/
|
||||
|
||||
/* Table 3: Call Management Functional Descriptor */
|
||||
struct usb_cdc_call_management_descriptor {
|
||||
uint8_t bFunctionLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bDescriptorSubtype;
|
||||
uint8_t bmCapabilities;
|
||||
uint8_t bDataInterface;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Table 4: Abstract Control Management Functional Descriptor */
|
||||
struct usb_cdc_acm_descriptor {
|
||||
uint8_t bFunctionLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bDescriptorSubtype;
|
||||
uint8_t bmCapabilities;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Table 13: Class-Specific Request Codes for PSTN subclasses */
|
||||
/* ... */
|
||||
#define USB_CDC_REQ_SET_LINE_CODING 0x20
|
||||
/* ... */
|
||||
#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22
|
||||
/* ... */
|
||||
|
||||
/* Table 17: Line Coding Structure */
|
||||
struct usb_cdc_line_coding {
|
||||
uint32_t dwDTERate;
|
||||
uint8_t bCharFormat;
|
||||
uint8_t bParityType;
|
||||
uint8_t bDataBits;
|
||||
} __attribute__((packed));
|
||||
|
||||
enum usb_cdc_line_coding_bCharFormat {
|
||||
USB_CDC_1_STOP_BITS = 0,
|
||||
USB_CDC_1_5_STOP_BITS = 1,
|
||||
USB_CDC_2_STOP_BITS = 2,
|
||||
};
|
||||
|
||||
enum usb_cdc_line_coding_bParityType {
|
||||
USB_CDC_NO_PARITY = 0,
|
||||
USB_CDC_ODD_PARITY = 1,
|
||||
USB_CDC_EVEN_PARITY = 2,
|
||||
USB_CDC_MARK_PARITY = 3,
|
||||
USB_CDC_SPACE_PARITY = 4,
|
||||
};
|
||||
|
||||
/* Table 30: Class-Specific Notification Codes for PSTN subclasses */
|
||||
/* ... */
|
||||
#define USB_CDC_NOTIFY_SERIAL_STATE 0x20
|
||||
/* ... */
|
||||
|
||||
/* Notification Structure */
|
||||
struct usb_cdc_notification {
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bNotification;
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif
|
||||
|
||||
/**@}*/
|
||||
|
101
sw/include/usb-desc.h
Normal file
101
sw/include/usb-desc.h
Normal file
@ -0,0 +1,101 @@
|
||||
/* Teensyduino Core Library
|
||||
* http://www.pjrc.com/teensy/
|
||||
* Copyright (c) 2013 PJRC.COM, LLC.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* 1. The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* 2. If the Software is incorporated into a build system that allows
|
||||
* selection among a list of target devices, then similar target
|
||||
* devices manufactured by PJRC.COM must be included in the list of
|
||||
* target devices and selectable in the same manner.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _usb_desc_h_
|
||||
#define _usb_desc_h_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct usb_setup_request {
|
||||
union {
|
||||
struct {
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bRequest;
|
||||
};
|
||||
uint16_t wRequestAndType;
|
||||
};
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
};
|
||||
|
||||
struct usb_string_descriptor_struct {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t wString[];
|
||||
};
|
||||
|
||||
#define NUM_USB_BUFFERS 8
|
||||
#define VENDOR_ID 0x1209 // pid.codes
|
||||
#define PRODUCT_ID 0x5bf0 // Assigned to Fomu project
|
||||
#define DEVICE_VER 0x0101 // Bootloader version
|
||||
#define MANUFACTURER_NAME u"Foosn"
|
||||
#define MANUFACTURER_NAME_LEN sizeof(MANUFACTURER_NAME)
|
||||
#define PRODUCT_NAME u"Fomu Factory Test " GIT_VERSION
|
||||
#define PRODUCT_NAME_LEN sizeof(PRODUCT_NAME)
|
||||
#define EP0_SIZE 64
|
||||
#define NUM_INTERFACE 1
|
||||
#define CONFIG_DESC_SIZE 67
|
||||
#define USB_DT_INTERFACE_SIZE 9
|
||||
|
||||
/* USB Descriptor Types - Table 9-5 */
|
||||
#define USB_DT_DEVICE 1
|
||||
#define USB_DT_CONFIGURATION 2
|
||||
#define USB_DT_STRING 3
|
||||
#define USB_DT_INTERFACE 4
|
||||
#define USB_DT_ENDPOINT 5
|
||||
#define USB_DT_DEVICE_QUALIFIER 6
|
||||
#define USB_DT_OTHER_SPEED_CONFIGURATION 7
|
||||
#define USB_DT_INTERFACE_POWER 8
|
||||
/* From ECNs */
|
||||
#define USB_DT_OTG 9
|
||||
#define USB_DT_DEBUG 10
|
||||
#define USB_DT_INTERFACE_ASSOCIATION 11
|
||||
|
||||
#define USB_DT_ENDPOINT_SIZE 7
|
||||
|
||||
/* USB Endpoint Descriptor bmAttributes bit definitions - Table 9-13 */
|
||||
/* bits 1..0 : transfer type */
|
||||
#define USB_ENDPOINT_ATTR_CONTROL 0x00
|
||||
#define USB_ENDPOINT_ATTR_ISOCHRONOUS 0x01
|
||||
#define USB_ENDPOINT_ATTR_BULK 0x02
|
||||
#define USB_ENDPOINT_ATTR_INTERRUPT 0x03
|
||||
#define USB_ENDPOINT_ATTR_TYPE 0x03
|
||||
|
||||
typedef struct {
|
||||
uint16_t wValue;
|
||||
uint16_t length;
|
||||
const uint8_t *addr;
|
||||
} usb_descriptor_list_t;
|
||||
|
||||
extern const usb_descriptor_list_t usb_descriptor_list[];
|
||||
|
||||
#endif
|
30
sw/include/usb.h
Normal file
30
sw/include/usb.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef __USB_H
|
||||
#define __USB_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct usb_setup_request;
|
||||
|
||||
void usb_isr(void);
|
||||
void usb_init(void);
|
||||
void usb_connect(void);
|
||||
void usb_idle(void);
|
||||
void usb_disconnect(void);
|
||||
|
||||
int usb_irq_happened(void);
|
||||
void usb_setup(const struct usb_setup_request *setup);
|
||||
void usb_send(const void *data, int total_count);
|
||||
void usb_ack_in(void);
|
||||
void usb_ack_out(void);
|
||||
void usb_err(void);
|
||||
int usb_recv(void *buffer, unsigned int buffer_len);
|
||||
void usb_poll(void);
|
||||
void usb_wait_for_send_done(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
55
sw/ld/linker.ld
Normal file
55
sw/ld/linker.ld
Normal file
@ -0,0 +1,55 @@
|
||||
INCLUDE output_format.ld
|
||||
ENTRY(_start)
|
||||
|
||||
__DYNAMIC = 0;
|
||||
|
||||
INCLUDE regions.ld
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
_ftext = .;
|
||||
*(.text.start)
|
||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||
_etext = .;
|
||||
} > rom
|
||||
|
||||
.rodata :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_frodata = .;
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||
*(.rodata1)
|
||||
*(.srodata)
|
||||
_erodata = .;
|
||||
} > rom
|
||||
|
||||
.data : AT (ADDR(.rodata) + SIZEOF (.rodata))
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_fdata = .;
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
*(.data1)
|
||||
_gp = ALIGN(16);
|
||||
*(.sdata .sdata.* .gnu.linkonce.s.* .sdata2 .sdata2.*)
|
||||
_edata = ALIGN(16); /* Make sure _edata is >= _gp. */
|
||||
} > sram
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_fbss = .;
|
||||
*(.dynsbss)
|
||||
*(.sbss .sbss.* .gnu.linkonce.sb.*)
|
||||
*(.scommon)
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_ebss = .;
|
||||
_end = .;
|
||||
} > sram
|
||||
}
|
||||
|
||||
PROVIDE(_fstack = ORIGIN(sram) + LENGTH(sram) - 4);
|
1
sw/ld/output_format.ld
Normal file
1
sw/ld/output_format.ld
Normal file
@ -0,0 +1 @@
|
||||
OUTPUT_FORMAT("elf32-littleriscv")
|
4
sw/ld/regions.ld
Normal file
4
sw/ld/regions.ld
Normal file
@ -0,0 +1,4 @@
|
||||
MEMORY {
|
||||
sram : ORIGIN = 0x10000000, LENGTH = 4096
|
||||
rom : ORIGIN = 0x00000000, LENGTH = 0x00002000
|
||||
}
|
91
sw/src/crt0-vexriscv.S
Normal file
91
sw/src/crt0-vexriscv.S
Normal file
@ -0,0 +1,91 @@
|
||||
.global main
|
||||
.global isr
|
||||
|
||||
.section .text.start
|
||||
.global _start
|
||||
|
||||
_start:
|
||||
j crt_init
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
.section .text
|
||||
.global trap_entry
|
||||
trap_entry:
|
||||
sw x1, - 1*4(sp)
|
||||
sw x5, - 2*4(sp)
|
||||
sw x6, - 3*4(sp)
|
||||
sw x7, - 4*4(sp)
|
||||
sw x10, - 5*4(sp)
|
||||
sw x11, - 6*4(sp)
|
||||
sw x12, - 7*4(sp)
|
||||
sw x13, - 8*4(sp)
|
||||
sw x14, - 9*4(sp)
|
||||
sw x15, -10*4(sp)
|
||||
sw x16, -11*4(sp)
|
||||
sw x17, -12*4(sp)
|
||||
sw x28, -13*4(sp)
|
||||
sw x29, -14*4(sp)
|
||||
sw x30, -15*4(sp)
|
||||
sw x31, -16*4(sp)
|
||||
addi sp,sp,-16*4
|
||||
call isr
|
||||
lw x1 , 15*4(sp)
|
||||
lw x5, 14*4(sp)
|
||||
lw x6, 13*4(sp)
|
||||
lw x7, 12*4(sp)
|
||||
lw x10, 11*4(sp)
|
||||
lw x11, 10*4(sp)
|
||||
lw x12, 9*4(sp)
|
||||
lw x13, 8*4(sp)
|
||||
lw x14, 7*4(sp)
|
||||
lw x15, 6*4(sp)
|
||||
lw x16, 5*4(sp)
|
||||
lw x17, 4*4(sp)
|
||||
lw x28, 3*4(sp)
|
||||
lw x29, 2*4(sp)
|
||||
lw x30, 1*4(sp)
|
||||
lw x31, 0*4(sp)
|
||||
addi sp,sp,16*4
|
||||
mret
|
||||
.text
|
||||
|
||||
|
||||
crt_init:
|
||||
la sp, _fstack + 4
|
||||
la a0, trap_entry
|
||||
csrw mtvec, a0
|
||||
|
||||
bss_init:
|
||||
la a0, _fbss
|
||||
la a1, _ebss
|
||||
bss_loop:
|
||||
beq a0,a1,bss_done
|
||||
sw zero,0(a0)
|
||||
add a0,a0,4
|
||||
j bss_loop
|
||||
bss_done:
|
||||
|
||||
/* Load DATA */
|
||||
la t0, _erodata
|
||||
la t1, _fdata
|
||||
la t2, _edata
|
||||
3:
|
||||
lw t3, 0(t0)
|
||||
sw t3, 0(t1)
|
||||
/* _edata is aligned to 16 bytes. Use word-xfers. */
|
||||
addi t0, t0, 4
|
||||
addi t1, t1, 4
|
||||
bltu t1, t2, 3b
|
||||
|
||||
li a0, 0x880 //880 enable timer + external interrupt sources (until mstatus.MIE is set, they will never trigger an interrupt)
|
||||
csrw mie,a0
|
||||
|
||||
call main
|
||||
infinit_loop:
|
||||
j infinit_loop
|
46
sw/src/main.c
Normal file
46
sw/src/main.c
Normal file
@ -0,0 +1,46 @@
|
||||
#include <stdio.h>
|
||||
#include <irq.h>
|
||||
#include <usb.h>
|
||||
#include <time.h>
|
||||
#include <rgb.h>
|
||||
#include <spi.h>
|
||||
#include <fomu/csr.h>
|
||||
|
||||
struct ff_spi *spi;
|
||||
|
||||
void isr(void)
|
||||
{
|
||||
unsigned int irqs;
|
||||
|
||||
irqs = irq_pending() & irq_getmask();
|
||||
|
||||
if (irqs & (1 << USB_INTERRUPT))
|
||||
usb_isr();
|
||||
}
|
||||
|
||||
static void init(void)
|
||||
{
|
||||
rgb_init();
|
||||
spi = spiAlloc();
|
||||
spiInit(spi);
|
||||
irq_setmask(0);
|
||||
irq_setie(1);
|
||||
usb_init();
|
||||
time_init();
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
init();
|
||||
|
||||
usb_connect();
|
||||
while (1)
|
||||
{
|
||||
usb_poll();
|
||||
}
|
||||
return 0;
|
||||
}
|
89
sw/src/rgb.c
Normal file
89
sw/src/rgb.c
Normal file
@ -0,0 +1,89 @@
|
||||
#include <rgb.h>
|
||||
#include <fomu/csr.h>
|
||||
|
||||
enum led_registers {
|
||||
LEDDCR0 = 8,
|
||||
LEDDBR = 9,
|
||||
LEDDONR = 10,
|
||||
LEDDOFR = 11,
|
||||
LEDDBCRR = 5,
|
||||
LEDDBCFR = 6,
|
||||
LEDDPWRR = 1,
|
||||
LEDDPWRG = 2,
|
||||
LEDDPWRB = 3,
|
||||
};
|
||||
|
||||
#define BREATHE_ENABLE (1 << 7)
|
||||
#define BREATHE_EDGE_ON (0 << 6)
|
||||
#define BREATHE_EDGE_BOTH (1 << 6)
|
||||
#define BREATHE_MODE_MODULATE (1 << 5)
|
||||
#define BREATHE_RATE(x) ((x & 7) << 0)
|
||||
|
||||
#define RGB_SWITCH_MODE(x) do { \
|
||||
if (rgb_mode == x) \
|
||||
return; \
|
||||
rgb_mode = x; \
|
||||
/* Toggle LEDD_EXE to force the mode to switch */ \
|
||||
rgb_ctrl_write( (1 << 1) | (1 << 2)); \
|
||||
rgb_ctrl_write((1 << 0) | (1 << 1) | (1 << 2)); \
|
||||
} while(0)
|
||||
|
||||
static enum {
|
||||
INVALID = 0,
|
||||
IDLE,
|
||||
WRITING,
|
||||
ERROR,
|
||||
DONE,
|
||||
} rgb_mode;
|
||||
|
||||
static void rgb_write(uint8_t value, uint8_t addr) {
|
||||
rgb_addr_write(addr);
|
||||
rgb_dat_write(value);
|
||||
}
|
||||
|
||||
void rgb_init(void) {
|
||||
// Turn on the RGB block and current enable, as well as enabling led control
|
||||
rgb_ctrl_write((1 << 0) | (1 << 1) | (1 << 2));
|
||||
|
||||
// Enable the LED driver, and set 250 Hz mode.
|
||||
// Also set quick stop, which we'll use to switch patterns quickly.
|
||||
rgb_write((1 << 7) | (1 << 6) | (1 << 3), LEDDCR0);
|
||||
|
||||
// Set clock register to 12 MHz / 64 kHz - 1
|
||||
rgb_write((12000000/64000)-1, LEDDBR);
|
||||
|
||||
rgb_mode_idle();
|
||||
}
|
||||
|
||||
static void rgb_switch_mode(uint8_t mode,
|
||||
uint8_t onr, uint8_t ofr,
|
||||
uint8_t onrate, uint8_t offrate,
|
||||
uint8_t r, uint8_t g, uint8_t b) {
|
||||
RGB_SWITCH_MODE(mode);
|
||||
rgb_write(onr, LEDDONR);
|
||||
rgb_write(ofr, LEDDOFR);
|
||||
|
||||
rgb_write(BREATHE_ENABLE | BREATHE_EDGE_BOTH
|
||||
| BREATHE_MODE_MODULATE | BREATHE_RATE(onrate), LEDDBCRR);
|
||||
rgb_write(BREATHE_ENABLE | BREATHE_MODE_MODULATE | BREATHE_RATE(offrate), LEDDBCFR);
|
||||
|
||||
rgb_write(r, LEDDPWRG); // Red
|
||||
rgb_write(g, LEDDPWRB); // Green
|
||||
rgb_write(b, LEDDPWRR); // Blue
|
||||
}
|
||||
|
||||
void rgb_mode_idle(void) {
|
||||
rgb_switch_mode(IDLE, 12, 14, 2, 3, 0x00/4, 0x4a/4, 0xe1/4);
|
||||
}
|
||||
|
||||
void rgb_mode_writing(void) {
|
||||
rgb_switch_mode(WRITING, 1, 2, 1, 3, 0x00/4, 0x7a/4, 0x51/4);
|
||||
}
|
||||
|
||||
void rgb_mode_error(void) {
|
||||
rgb_switch_mode(ERROR, 3, 3, 2, 3, 0xf0/4, 0x0a/4, 0x01/4);
|
||||
}
|
||||
|
||||
void rgb_mode_done(void) {
|
||||
rgb_switch_mode(DONE, 8, 8, 2, 3, 0x14/4, 0xff/4, 0x44/4);
|
||||
}
|
824
sw/src/spi.c
Normal file
824
sw/src/spi.c
Normal file
@ -0,0 +1,824 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <fomu/csr.h>
|
||||
|
||||
#include "spi.h"
|
||||
|
||||
#define fprintf(...) do {} while(0)
|
||||
|
||||
static uint8_t do_mirror;
|
||||
static uint8_t oe_mirror;
|
||||
|
||||
#define PI_OUTPUT 1
|
||||
#define PI_INPUT 0
|
||||
#define PI_ALT0 PI_INPUT
|
||||
static void gpioSetMode(int pin, int mode) {
|
||||
if (mode)
|
||||
oe_mirror |= 1 << pin;
|
||||
else
|
||||
oe_mirror &= ~(1 << pin);
|
||||
picorvspi_cfg2_write(oe_mirror);
|
||||
}
|
||||
|
||||
static void gpioWrite(int pin, int val) {
|
||||
if (val)
|
||||
do_mirror |= 1 << pin;
|
||||
else
|
||||
do_mirror &= ~(1 << pin);
|
||||
picorvspi_cfg1_write(do_mirror);
|
||||
}
|
||||
|
||||
static int gpioRead(int pin) {
|
||||
return !!(picorvspi_stat1_read() & (1 << pin));
|
||||
}
|
||||
|
||||
static void gpioSync(void) {
|
||||
// bbspi_do_write(do_mirror);
|
||||
}
|
||||
|
||||
#define SPI_ONLY_SINGLE
|
||||
|
||||
enum ff_spi_quirks {
|
||||
// There is no separate "Write SR 2" command. Instead,
|
||||
// you must write SR2 after writing SR1
|
||||
SQ_SR2_FROM_SR1 = (1 << 0),
|
||||
|
||||
// Don't issue a "Write Enable" command prior to writing
|
||||
// a status register
|
||||
SQ_SKIP_SR_WEL = (1 << 1),
|
||||
|
||||
// Security registers are shifted up by 4 bits
|
||||
SQ_SECURITY_NYBBLE_SHIFT = (1 << 2),
|
||||
};
|
||||
|
||||
struct ff_spi {
|
||||
enum spi_state state;
|
||||
enum spi_type type;
|
||||
enum spi_type desired_type;
|
||||
struct spi_id id;
|
||||
enum ff_spi_quirks quirks;
|
||||
int size_override;
|
||||
|
||||
struct {
|
||||
int clk;
|
||||
int d0;
|
||||
int d1;
|
||||
int d2;
|
||||
int d3;
|
||||
int wp;
|
||||
int hold;
|
||||
int cs;
|
||||
int miso;
|
||||
int mosi;
|
||||
} pins;
|
||||
};
|
||||
|
||||
static void spi_get_id(struct ff_spi *spi);
|
||||
|
||||
static void spi_set_state(struct ff_spi *spi, enum spi_state state) {
|
||||
return;
|
||||
if (spi->state == state)
|
||||
return;
|
||||
#ifndef SPI_ONLY_SINGLE
|
||||
switch (state) {
|
||||
case SS_SINGLE:
|
||||
#endif
|
||||
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
|
||||
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
|
||||
gpioSetMode(spi->pins.mosi, PI_OUTPUT); // MOSI
|
||||
gpioSetMode(spi->pins.miso, PI_INPUT); // MISO
|
||||
gpioSetMode(spi->pins.hold, PI_OUTPUT);
|
||||
gpioSetMode(spi->pins.wp, PI_OUTPUT);
|
||||
#ifndef SPI_ONLY_SINGLE
|
||||
break;
|
||||
|
||||
case SS_DUAL_RX:
|
||||
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
|
||||
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
|
||||
gpioSetMode(spi->pins.mosi, PI_INPUT); // MOSI
|
||||
gpioSetMode(spi->pins.miso, PI_INPUT); // MISO
|
||||
gpioSetMode(spi->pins.hold, PI_OUTPUT);
|
||||
gpioSetMode(spi->pins.wp, PI_OUTPUT);
|
||||
break;
|
||||
|
||||
case SS_DUAL_TX:
|
||||
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
|
||||
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
|
||||
gpioSetMode(spi->pins.mosi, PI_OUTPUT); // MOSI
|
||||
gpioSetMode(spi->pins.miso, PI_OUTPUT); // MISO
|
||||
gpioSetMode(spi->pins.hold, PI_OUTPUT);
|
||||
gpioSetMode(spi->pins.wp, PI_OUTPUT);
|
||||
break;
|
||||
|
||||
case SS_QUAD_RX:
|
||||
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
|
||||
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
|
||||
gpioSetMode(spi->pins.mosi, PI_INPUT); // MOSI
|
||||
gpioSetMode(spi->pins.miso, PI_INPUT); // MISO
|
||||
gpioSetMode(spi->pins.hold, PI_INPUT);
|
||||
gpioSetMode(spi->pins.wp, PI_INPUT);
|
||||
break;
|
||||
|
||||
case SS_QUAD_TX:
|
||||
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
|
||||
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
|
||||
gpioSetMode(spi->pins.mosi, PI_OUTPUT); // MOSI
|
||||
gpioSetMode(spi->pins.miso, PI_OUTPUT); // MISO
|
||||
gpioSetMode(spi->pins.hold, PI_OUTPUT);
|
||||
gpioSetMode(spi->pins.wp, PI_OUTPUT);
|
||||
break;
|
||||
|
||||
case SS_HARDWARE:
|
||||
gpioSetMode(spi->pins.clk, PI_ALT0); // CLK
|
||||
gpioSetMode(spi->pins.cs, PI_ALT0); // CE0#
|
||||
gpioSetMode(spi->pins.mosi, PI_ALT0); // MOSI
|
||||
gpioSetMode(spi->pins.miso, PI_ALT0); // MISO
|
||||
gpioSetMode(spi->pins.hold, PI_OUTPUT);
|
||||
gpioSetMode(spi->pins.wp, PI_OUTPUT);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Unrecognized spi state\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
spi->state = state;
|
||||
}
|
||||
|
||||
void spiPause(struct ff_spi *spi) {
|
||||
(void)spi;
|
||||
gpioSync();
|
||||
// usleep(1);
|
||||
return;
|
||||
}
|
||||
|
||||
void spiBegin(struct ff_spi *spi) {
|
||||
spi_set_state(spi, SS_SINGLE);
|
||||
if ((spi->type == ST_SINGLE) || (spi->type == ST_DUAL)) {
|
||||
gpioWrite(spi->pins.wp, 1);
|
||||
gpioWrite(spi->pins.hold, 1);
|
||||
}
|
||||
gpioWrite(spi->pins.cs, 0);
|
||||
}
|
||||
|
||||
void spiEnd(struct ff_spi *spi) {
|
||||
(void)spi;
|
||||
gpioWrite(spi->pins.cs, 1);
|
||||
}
|
||||
|
||||
static uint8_t spiXfer(struct ff_spi *spi, uint8_t out) {
|
||||
int bit;
|
||||
uint8_t in = 0;
|
||||
|
||||
for (bit = 7; bit >= 0; bit--) {
|
||||
if (out & (1 << bit)) {
|
||||
gpioWrite(spi->pins.mosi, 1);
|
||||
}
|
||||
else {
|
||||
gpioWrite(spi->pins.mosi, 0);
|
||||
}
|
||||
gpioWrite(spi->pins.clk, 1);
|
||||
spiPause(spi);
|
||||
in |= ((!!gpioRead(spi->pins.miso)) << bit);
|
||||
gpioWrite(spi->pins.clk, 0);
|
||||
spiPause(spi);
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
static void spiSingleTx(struct ff_spi *spi, uint8_t out) {
|
||||
spi_set_state(spi, SS_SINGLE);
|
||||
spiXfer(spi, out);
|
||||
}
|
||||
|
||||
static uint8_t spiSingleRx(struct ff_spi *spi) {
|
||||
spi_set_state(spi, SS_SINGLE);
|
||||
return spiXfer(spi, 0xff);
|
||||
}
|
||||
|
||||
static void spiDualTx(struct ff_spi *spi, uint8_t out) {
|
||||
|
||||
int bit;
|
||||
spi_set_state(spi, SS_DUAL_TX);
|
||||
for (bit = 7; bit >= 0; bit -= 2) {
|
||||
if (out & (1 << (bit - 1))) {
|
||||
gpioWrite(spi->pins.d0, 1);
|
||||
}
|
||||
else {
|
||||
gpioWrite(spi->pins.d0, 0);
|
||||
}
|
||||
|
||||
if (out & (1 << (bit - 0))) {
|
||||
gpioWrite(spi->pins.d1, 1);
|
||||
}
|
||||
else {
|
||||
gpioWrite(spi->pins.d1, 0);
|
||||
}
|
||||
gpioWrite(spi->pins.clk, 1);
|
||||
spiPause(spi);
|
||||
gpioWrite(spi->pins.clk, 0);
|
||||
spiPause(spi);
|
||||
}
|
||||
}
|
||||
|
||||
static void spiQuadTx(struct ff_spi *spi, uint8_t out) {
|
||||
int bit;
|
||||
spi_set_state(spi, SS_QUAD_TX);
|
||||
for (bit = 7; bit >= 0; bit -= 4) {
|
||||
if (out & (1 << (bit - 3))) {
|
||||
gpioWrite(spi->pins.d0, 1);
|
||||
}
|
||||
else {
|
||||
gpioWrite(spi->pins.d0, 0);
|
||||
}
|
||||
|
||||
if (out & (1 << (bit - 2))) {
|
||||
gpioWrite(spi->pins.d1, 1);
|
||||
}
|
||||
else {
|
||||
gpioWrite(spi->pins.d1, 0);
|
||||
}
|
||||
|
||||
if (out & (1 << (bit - 1))) {
|
||||
gpioWrite(spi->pins.d2, 1);
|
||||
}
|
||||
else {
|
||||
gpioWrite(spi->pins.d2, 0);
|
||||
}
|
||||
|
||||
if (out & (1 << (bit - 0))) {
|
||||
gpioWrite(spi->pins.d3, 1);
|
||||
}
|
||||
else {
|
||||
gpioWrite(spi->pins.d3, 0);
|
||||
}
|
||||
gpioWrite(spi->pins.clk, 1);
|
||||
spiPause(spi);
|
||||
gpioWrite(spi->pins.clk, 0);
|
||||
spiPause(spi);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t spiDualRx(struct ff_spi *spi) {
|
||||
int bit;
|
||||
uint8_t in = 0;
|
||||
|
||||
spi_set_state(spi, SS_QUAD_RX);
|
||||
for (bit = 7; bit >= 0; bit -= 2) {
|
||||
gpioWrite(spi->pins.clk, 1);
|
||||
spiPause(spi);
|
||||
in |= ((!!gpioRead(spi->pins.d0)) << (bit - 1));
|
||||
in |= ((!!gpioRead(spi->pins.d1)) << (bit - 0));
|
||||
gpioWrite(spi->pins.clk, 0);
|
||||
spiPause(spi);
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
static uint8_t spiQuadRx(struct ff_spi *spi) {
|
||||
int bit;
|
||||
uint8_t in = 0;
|
||||
|
||||
spi_set_state(spi, SS_QUAD_RX);
|
||||
for (bit = 7; bit >= 0; bit -= 4) {
|
||||
gpioWrite(spi->pins.clk, 1);
|
||||
spiPause(spi);
|
||||
in |= ((!!gpioRead(spi->pins.d0)) << (bit - 3));
|
||||
in |= ((!!gpioRead(spi->pins.d1)) << (bit - 2));
|
||||
in |= ((!!gpioRead(spi->pins.d2)) << (bit - 1));
|
||||
in |= ((!!gpioRead(spi->pins.d3)) << (bit - 0));
|
||||
gpioWrite(spi->pins.clk, 0);
|
||||
spiPause(spi);
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
int spiTx(struct ff_spi *spi, uint8_t word) {
|
||||
switch (spi->type) {
|
||||
case ST_SINGLE:
|
||||
spiSingleTx(spi, word);
|
||||
break;
|
||||
case ST_DUAL:
|
||||
spiDualTx(spi, word);
|
||||
break;
|
||||
case ST_QUAD:
|
||||
case ST_QPI:
|
||||
spiQuadTx(spi, word);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t spiRx(struct ff_spi *spi) {
|
||||
switch (spi->type) {
|
||||
case ST_SINGLE:
|
||||
return spiSingleRx(spi);
|
||||
case ST_DUAL:
|
||||
return spiDualRx(spi);
|
||||
case ST_QUAD:
|
||||
case ST_QPI:
|
||||
return spiQuadRx(spi);
|
||||
default:
|
||||
return 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
void spiCommand(struct ff_spi *spi, uint8_t cmd) {
|
||||
if (spi->type == ST_QPI)
|
||||
spiQuadTx(spi, cmd);
|
||||
else
|
||||
spiSingleTx(spi, cmd);
|
||||
}
|
||||
|
||||
uint8_t spiCommandRx(struct ff_spi *spi) {
|
||||
if (spi->type == ST_QPI)
|
||||
return spiQuadRx(spi);
|
||||
else
|
||||
return spiSingleRx(spi);
|
||||
}
|
||||
|
||||
uint8_t spiReadStatus(struct ff_spi *spi, uint8_t sr) {
|
||||
uint8_t val = 0xff;
|
||||
(void)sr;
|
||||
|
||||
#if 0
|
||||
switch (sr) {
|
||||
case 1:
|
||||
#endif
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x05);
|
||||
val = spiCommandRx(spi);
|
||||
spiEnd(spi);
|
||||
#if 0
|
||||
break;
|
||||
|
||||
case 2:
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x35);
|
||||
val = spiCommandRx(spi);
|
||||
spiEnd(spi);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x15);
|
||||
val = spiCommandRx(spi);
|
||||
spiEnd(spi);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "unrecognized status register: %d\n", sr);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
void spiWriteSecurity(struct ff_spi *spi, uint8_t sr, uint8_t security[256]) {
|
||||
|
||||
if (spi->quirks & SQ_SECURITY_NYBBLE_SHIFT)
|
||||
sr <<= 4;
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x06);
|
||||
spiEnd(spi);
|
||||
|
||||
// erase the register
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x44);
|
||||
spiCommand(spi, 0x00); // A23-16
|
||||
spiCommand(spi, sr); // A15-8
|
||||
spiCommand(spi, 0x00); // A0-7
|
||||
spiEnd(spi);
|
||||
|
||||
spi_get_id(spi);
|
||||
sleep(1);
|
||||
|
||||
// write enable
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x06);
|
||||
spiEnd(spi);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x42);
|
||||
spiCommand(spi, 0x00); // A23-16
|
||||
spiCommand(spi, sr); // A15-8
|
||||
spiCommand(spi, 0x00); // A0-7
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
spiCommand(spi, security[i]);
|
||||
spiEnd(spi);
|
||||
|
||||
spi_get_id(spi);
|
||||
}
|
||||
|
||||
void spiReadSecurity(struct ff_spi *spi, uint8_t sr, uint8_t security[256]) {
|
||||
if (spi->quirks & SQ_SECURITY_NYBBLE_SHIFT)
|
||||
sr <<= 4;
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x48); // Read security registers
|
||||
spiCommand(spi, 0x00); // A23-16
|
||||
spiCommand(spi, sr); // A15-8
|
||||
spiCommand(spi, 0x00); // A0-7
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
security[i] = spiCommandRx(spi);
|
||||
spiEnd(spi);
|
||||
}
|
||||
|
||||
void spiWriteStatus(struct ff_spi *spi, uint8_t sr, uint8_t val) {
|
||||
|
||||
switch (sr) {
|
||||
case 1:
|
||||
if (!(spi->quirks & SQ_SKIP_SR_WEL)) {
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x06);
|
||||
spiEnd(spi);
|
||||
}
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x50);
|
||||
spiEnd(spi);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x01);
|
||||
spiCommand(spi, val);
|
||||
spiEnd(spi);
|
||||
break;
|
||||
|
||||
case 2: {
|
||||
uint8_t sr1 = 0x00;
|
||||
if (spi->quirks & SQ_SR2_FROM_SR1)
|
||||
sr1 = spiReadStatus(spi, 1);
|
||||
|
||||
if (!(spi->quirks & SQ_SKIP_SR_WEL)) {
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x06);
|
||||
spiEnd(spi);
|
||||
}
|
||||
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x50);
|
||||
spiEnd(spi);
|
||||
|
||||
spiBegin(spi);
|
||||
if (spi->quirks & SQ_SR2_FROM_SR1) {
|
||||
spiCommand(spi, 0x01);
|
||||
spiCommand(spi, sr1);
|
||||
spiCommand(spi, val);
|
||||
}
|
||||
else {
|
||||
spiCommand(spi, 0x31);
|
||||
spiCommand(spi, val);
|
||||
}
|
||||
spiEnd(spi);
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
if (!(spi->quirks & SQ_SKIP_SR_WEL)) {
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x06);
|
||||
spiEnd(spi);
|
||||
}
|
||||
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x50);
|
||||
spiEnd(spi);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x11);
|
||||
spiCommand(spi, val);
|
||||
spiEnd(spi);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "unrecognized status register: %d\n", sr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
struct spi_id spiId(struct ff_spi *spi) {
|
||||
return spi->id;
|
||||
}
|
||||
|
||||
static void spi_decode_id(struct ff_spi *spi) {
|
||||
spi->id.bytes = -1; // unknown
|
||||
|
||||
if (spi->id.manufacturer_id == 0xef) {
|
||||
// spi->id.manufacturer = "Winbond";
|
||||
if ((spi->id.memory_type == 0x70)
|
||||
&& (spi->id.memory_size == 0x18)) {
|
||||
// spi->id.model = "W25Q128JV";
|
||||
// spi->id.capacity = "128 Mbit";
|
||||
spi->id.bytes = 16 * 1024 * 1024;
|
||||
}
|
||||
}
|
||||
|
||||
if (spi->id.manufacturer_id == 0x1f) {
|
||||
// spi->id.manufacturer = "Adesto";
|
||||
if ((spi->id.memory_type == 0x86)
|
||||
&& (spi->id.memory_size == 0x01)) {
|
||||
// spi->id.model = "AT25SF161";
|
||||
// spi->id.capacity = "16 Mbit";
|
||||
spi->id.bytes = 1 * 1024 * 1024;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
static void spi_get_id(struct ff_spi *spi) {
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x90); // Read manufacturer ID
|
||||
spiCommand(spi, 0x00); // Dummy byte 1
|
||||
spiCommand(spi, 0x00); // Dummy byte 2
|
||||
spiCommand(spi, 0x00); // Dummy byte 3
|
||||
spi->id.manufacturer_id = spiCommandRx(spi);
|
||||
spi->id.device_id = spiCommandRx(spi);
|
||||
spiEnd(spi);
|
||||
return;
|
||||
#if 0
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x9f); // Read device id
|
||||
spi->id._manufacturer_id = spiCommandRx(spi);
|
||||
spi->id.memory_type = spiCommandRx(spi);
|
||||
spi->id.memory_size = spiCommandRx(spi);
|
||||
spiEnd(spi);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0xab); // Read electronic signature
|
||||
spiCommand(spi, 0x00); // Dummy byte 1
|
||||
spiCommand(spi, 0x00); // Dummy byte 2
|
||||
spiCommand(spi, 0x00); // Dummy byte 3
|
||||
spi->id.signature = spiCommandRx(spi);
|
||||
spiEnd(spi);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x4b); // Read unique ID
|
||||
spiCommand(spi, 0x00); // Dummy byte 1
|
||||
spiCommand(spi, 0x00); // Dummy byte 2
|
||||
spiCommand(spi, 0x00); // Dummy byte 3
|
||||
spiCommand(spi, 0x00); // Dummy byte 4
|
||||
spi->id.serial[0] = spiCommandRx(spi);
|
||||
spi->id.serial[1] = spiCommandRx(spi);
|
||||
spi->id.serial[2] = spiCommandRx(spi);
|
||||
spi->id.serial[3] = spiCommandRx(spi);
|
||||
spiEnd(spi);
|
||||
|
||||
spi_decode_id(spi);
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
void spiOverrideSize(struct ff_spi *spi, uint32_t size) {
|
||||
spi->size_override = size;
|
||||
|
||||
// If size is 0, re-read the capacity
|
||||
if (!size)
|
||||
spi_decode_id(spi);
|
||||
else
|
||||
spi->id.bytes = size;
|
||||
}
|
||||
#endif
|
||||
|
||||
int spiSetType(struct ff_spi *spi, enum spi_type type) {
|
||||
|
||||
if (spi->type == type)
|
||||
return 0;
|
||||
|
||||
#ifndef SPI_ONLY_SINGLE
|
||||
switch (type) {
|
||||
|
||||
case ST_SINGLE:
|
||||
#endif
|
||||
if (spi->type == ST_QPI) {
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0xff); // Exit QPI Mode
|
||||
spiEnd(spi);
|
||||
}
|
||||
spi->type = type;
|
||||
spi_set_state(spi, SS_SINGLE);
|
||||
#ifndef SPI_ONLY_SINGLE
|
||||
break;
|
||||
|
||||
case ST_DUAL:
|
||||
if (spi->type == ST_QPI) {
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0xff); // Exit QPI Mode
|
||||
spiEnd(spi);
|
||||
}
|
||||
spi->type = type;
|
||||
spi_set_state(spi, SS_DUAL_TX);
|
||||
break;
|
||||
|
||||
case ST_QUAD:
|
||||
if (spi->type == ST_QPI) {
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0xff); // Exit QPI Mode
|
||||
spiEnd(spi);
|
||||
}
|
||||
|
||||
// Enable QE bit
|
||||
spiWriteStatus(spi, 2, spiReadStatus(spi, 2) | (1 << 1));
|
||||
|
||||
spi->type = type;
|
||||
spi_set_state(spi, SS_QUAD_TX);
|
||||
break;
|
||||
|
||||
case ST_QPI:
|
||||
// Enable QE bit
|
||||
spiWriteStatus(spi, 2, spiReadStatus(spi, 2) | (1 << 1));
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x38); // Enter QPI Mode
|
||||
spiEnd(spi);
|
||||
spi->type = type;
|
||||
spi_set_state(spi, SS_QUAD_TX);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Unrecognized SPI type: %d\n", type);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spiIsBusy(struct ff_spi *spi) {
|
||||
return spiReadStatus(spi, 1) & (1 << 0);
|
||||
}
|
||||
|
||||
int spiBeginErase32(struct ff_spi *spi, uint32_t erase_addr) {
|
||||
// Enable Write-Enable Latch (WEL)
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x06);
|
||||
spiEnd(spi);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x52);
|
||||
spiCommand(spi, erase_addr >> 16);
|
||||
spiCommand(spi, erase_addr >> 8);
|
||||
spiCommand(spi, erase_addr >> 0);
|
||||
spiEnd(spi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spiBeginErase64(struct ff_spi *spi, uint32_t erase_addr) {
|
||||
// Enable Write-Enable Latch (WEL)
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x06);
|
||||
spiEnd(spi);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0xD8);
|
||||
spiCommand(spi, erase_addr >> 16);
|
||||
spiCommand(spi, erase_addr >> 8);
|
||||
spiCommand(spi, erase_addr >> 0);
|
||||
spiEnd(spi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spiBeginWrite(struct ff_spi *spi, uint32_t addr, const void *v_data, unsigned int count) {
|
||||
const uint8_t write_cmd = 0x02;
|
||||
const uint8_t *data = v_data;
|
||||
unsigned int i;
|
||||
|
||||
// Enable Write-Enable Latch (WEL)
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x06);
|
||||
spiEnd(spi);
|
||||
|
||||
// uint8_t sr1 = spiReadStatus(spi, 1);
|
||||
// if (!(sr1 & (1 << 1)))
|
||||
// fprintf(stderr, "error: write-enable latch (WEL) not set, write will probably fail\n");
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, write_cmd);
|
||||
spiCommand(spi, addr >> 16);
|
||||
spiCommand(spi, addr >> 8);
|
||||
spiCommand(spi, addr >> 0);
|
||||
for (i = 0; (i < count) && (i < 256); i++)
|
||||
spiTx(spi, *data++);
|
||||
spiEnd(spi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t spiReset(struct ff_spi *spi) {
|
||||
// XXX You should check the "Ready" bit before doing this!
|
||||
|
||||
// Shift to QPI mode, then back to Single mode, to ensure
|
||||
// we're actually in Single mode.
|
||||
spiSetType(spi, ST_QPI);
|
||||
spiSetType(spi, ST_SINGLE);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x66); // "Enable Reset" command
|
||||
spiEnd(spi);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0x99); // "Reset Device" command
|
||||
spiEnd(spi);
|
||||
|
||||
// msleep(30);
|
||||
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0xab); // "Resume from Deep Power-Down" command
|
||||
spiEnd(spi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spiInit(struct ff_spi *spi) {
|
||||
spi->state = SS_UNCONFIGURED;
|
||||
spi->type = ST_UNCONFIGURED;
|
||||
|
||||
// Disable memory-mapped mode and enable bit-bang mode
|
||||
picorvspi_cfg4_write(0);
|
||||
|
||||
// Reset the SPI flash, which will return it to SPI mode even
|
||||
// if it's in QPI mode.
|
||||
spiReset(spi);
|
||||
|
||||
spiSetType(spi, ST_SINGLE);
|
||||
|
||||
// Have the SPI flash pay attention to us
|
||||
gpioWrite(spi->pins.hold, 1);
|
||||
|
||||
// Disable WP
|
||||
gpioWrite(spi->pins.wp, 1);
|
||||
|
||||
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
|
||||
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
|
||||
gpioSetMode(spi->pins.mosi, PI_OUTPUT); // MOSI
|
||||
gpioSetMode(spi->pins.miso, PI_INPUT); // MISO
|
||||
gpioSetMode(spi->pins.hold, PI_OUTPUT);
|
||||
gpioSetMode(spi->pins.wp, PI_OUTPUT);
|
||||
|
||||
spi_get_id(spi);
|
||||
|
||||
spi->quirks |= SQ_SR2_FROM_SR1;
|
||||
if (spi->id.manufacturer_id == 0xef)
|
||||
spi->quirks |= SQ_SKIP_SR_WEL | SQ_SECURITY_NYBBLE_SHIFT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spiEnableQuad(void) {
|
||||
struct ff_spi *spi = spiAlloc();
|
||||
spiInit(spi);
|
||||
spiWriteStatus(spi, 2, spiReadStatus(spi, 2) | (1 << 1));
|
||||
spiFree();
|
||||
}
|
||||
|
||||
struct ff_spi *spiAlloc(void) {
|
||||
static struct ff_spi spi;
|
||||
return &spi;
|
||||
}
|
||||
|
||||
void spiSetPin(struct ff_spi *spi, enum spi_pin pin, int val) {
|
||||
switch (pin) {
|
||||
case SP_MOSI: spi->pins.mosi = val; break;
|
||||
case SP_MISO: spi->pins.miso = val; break;
|
||||
case SP_HOLD: spi->pins.hold = val; break;
|
||||
case SP_WP: spi->pins.wp = val; break;
|
||||
case SP_CS: spi->pins.cs = val; break;
|
||||
case SP_CLK: spi->pins.clk = val; break;
|
||||
case SP_D0: spi->pins.d0 = val; break;
|
||||
case SP_D1: spi->pins.d1 = val; break;
|
||||
case SP_D2: spi->pins.d2 = val; break;
|
||||
case SP_D3: spi->pins.d3 = val; break;
|
||||
default: fprintf(stderr, "unrecognized pin: %d\n", pin); break;
|
||||
}
|
||||
}
|
||||
|
||||
void spiHold(struct ff_spi *spi) {
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0xb9);
|
||||
spiEnd(spi);
|
||||
}
|
||||
void spiUnhold(struct ff_spi *spi) {
|
||||
spiBegin(spi);
|
||||
spiCommand(spi, 0xab);
|
||||
spiEnd(spi);
|
||||
}
|
||||
|
||||
void spiFree(void) {
|
||||
// Re-enable memory-mapped mode
|
||||
picorvspi_cfg4_write(0x80);
|
||||
}
|
43
sw/src/time.c
Normal file
43
sw/src/time.c
Normal file
@ -0,0 +1,43 @@
|
||||
#include <fomu/csr.h>
|
||||
#include <time.h>
|
||||
|
||||
void time_init(void)
|
||||
{
|
||||
int t;
|
||||
|
||||
timer0_en_write(0);
|
||||
t = 2*SYSTEM_CLOCK_FREQUENCY;
|
||||
timer0_reload_write(t);
|
||||
timer0_load_write(t);
|
||||
timer0_en_write(1);
|
||||
}
|
||||
|
||||
int elapsed(int *last_event, int period)
|
||||
{
|
||||
int t, dt;
|
||||
|
||||
timer0_update_value_write(1);
|
||||
t = timer0_reload_read() - timer0_value_read();
|
||||
if(period < 0) {
|
||||
*last_event = t;
|
||||
return 1;
|
||||
}
|
||||
dt = t - *last_event;
|
||||
if(dt < 0)
|
||||
dt += timer0_reload_read();
|
||||
if((dt > period) || (dt < 0)) {
|
||||
*last_event = t;
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void msleep(int ms)
|
||||
{
|
||||
timer0_en_write(0);
|
||||
timer0_reload_write(0);
|
||||
timer0_load_write(SYSTEM_CLOCK_FREQUENCY/1000*ms);
|
||||
timer0_en_write(1);
|
||||
timer0_update_value_write(1);
|
||||
while(timer0_value_read()) timer0_update_value_write(1);
|
||||
}
|
220
sw/src/usb-desc.c
Normal file
220
sw/src/usb-desc.c
Normal file
@ -0,0 +1,220 @@
|
||||
/* Teensyduino Core Library
|
||||
* http://www.pjrc.com/teensy/
|
||||
* Copyright (c) 2013 PJRC.COM, LLC.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* 1. The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* 2. If the Software is incorporated into a build system that allows
|
||||
* selection among a list of target devices, then similar target
|
||||
* devices manufactured by PJRC.COM must be included in the list of
|
||||
* target devices and selectable in the same manner.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <usb-desc.h>
|
||||
#include <usb-cdc.h>
|
||||
|
||||
// USB Descriptors are binary data which the USB host reads to
|
||||
// automatically detect a USB device's capabilities. The format
|
||||
// and meaning of every field is documented in numerous USB
|
||||
// standards. When working with USB descriptors, despite the
|
||||
// complexity of the standards and poor writing quality in many
|
||||
// of those documents, remember descriptors are nothing more
|
||||
// than constant binary data that tells the USB host what the
|
||||
// device can do. Computers will load drivers based on this data.
|
||||
// Those drivers then communicate on the endpoints specified by
|
||||
// the descriptors.
|
||||
|
||||
// To configure a new combination of interfaces or make minor
|
||||
// changes to existing configuration (eg, change the name or ID
|
||||
// numbers), usually you would edit "usb_desc.h". This file
|
||||
// is meant to be configured by the header, so generally it is
|
||||
// only edited to add completely new USB interfaces or features.
|
||||
|
||||
// **************************************************************
|
||||
// USB Device
|
||||
// **************************************************************
|
||||
|
||||
#define LSB(n) ((n) & 255)
|
||||
#define MSB(n) (((n) >> 8) & 255)
|
||||
|
||||
// USB Device Descriptor. The USB host reads this first, to learn
|
||||
// what type of device is connected.
|
||||
static const uint8_t device_descriptor[] = {
|
||||
18, // bLength
|
||||
1, // bDescriptorType
|
||||
0x01, 0x02, // bcdUSB
|
||||
USB_CLASS_CDC, // bDeviceClass
|
||||
0x00, // bDeviceSubClass
|
||||
0x00, // bDeviceProtocol
|
||||
EP0_SIZE, // bMaxPacketSize0
|
||||
LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor
|
||||
LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct
|
||||
LSB(DEVICE_VER), MSB(DEVICE_VER), // bcdDevice
|
||||
1, // iManufacturer
|
||||
2, // iProduct
|
||||
0, // iSerialNumber
|
||||
1 // bNumConfigurations
|
||||
};
|
||||
|
||||
// These descriptors must NOT be "const", because the USB DMA
|
||||
// has trouble accessing flash memory with enough bandwidth
|
||||
// while the processor is executing from flash.
|
||||
|
||||
|
||||
// **************************************************************
|
||||
// USB Configuration
|
||||
// **************************************************************
|
||||
|
||||
// USB Configuration Descriptor. This huge descriptor tells all
|
||||
// of the devices capbilities.
|
||||
static const uint8_t config_descriptor[CONFIG_DESC_SIZE] = {
|
||||
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
|
||||
9, // bLength;
|
||||
2, // bDescriptorType;
|
||||
LSB(CONFIG_DESC_SIZE), // wTotalLength
|
||||
MSB(CONFIG_DESC_SIZE),
|
||||
NUM_INTERFACE, // bNumInterfaces
|
||||
1, // bConfigurationValue
|
||||
1, // iConfiguration
|
||||
0x80, // bmAttributes
|
||||
50, // bMaxPower
|
||||
|
||||
|
||||
// interface descriptor, CDC
|
||||
USB_DT_INTERFACE_SIZE, // bLength
|
||||
USB_DT_INTERFACE, // bDescriptorType
|
||||
0, // bInterfaceNumber
|
||||
0, // bAlternateSetting
|
||||
1, // bNumEndpoints
|
||||
USB_CLASS_CDC, // bInterfaceClass
|
||||
USB_CDC_SUBCLASS_ACM, // bInterfaceSubClass
|
||||
USB_CDC_PROTOCOL_AT, // bInterfaceProtocol
|
||||
0, // iInterface
|
||||
|
||||
// Header Functional Descriptor
|
||||
0x05, // bLength: Endpoint Descriptor size
|
||||
CS_INTERFACE, // bDescriptorType: CS_INTERFACE
|
||||
USB_CDC_TYPE_HEADER, // bDescriptorSubtype: Header Func Desc
|
||||
0x10, // bcdCDC: spec release number
|
||||
0x01,
|
||||
|
||||
// Call Managment Functional Descriptor
|
||||
0x05, // bFunctionLength
|
||||
CS_INTERFACE, // bDescriptorType: CS_INTERFACE
|
||||
USB_CDC_TYPE_CALL_MANAGEMENT, // bDescriptorSubtype: Call Management Func Desc
|
||||
0, // bmCapabilities: D0+D1
|
||||
1, // bDataInterface: 1
|
||||
|
||||
// ACM Functional Descriptor
|
||||
0x04, // bFunctionLength
|
||||
CS_INTERFACE, // bDescriptorType: CS_INTERFACE
|
||||
USB_CDC_TYPE_ACM, // bDescriptorSubtype: Abstract Control Management desc
|
||||
6, // bmCapabilities
|
||||
|
||||
// Union Functional Descriptor
|
||||
0x05, // bFunctionLength
|
||||
CS_INTERFACE, // bDescriptorType: CS_INTERFACE
|
||||
USB_CDC_TYPE_UNION, // bDescriptorSubtype: Union func desc
|
||||
0, // bMasterInterface: Communication class interface
|
||||
1, // bSlaveInterface0: Data Class Interface
|
||||
|
||||
// Endpoint descriptor
|
||||
USB_DT_ENDPOINT_SIZE, // bLength
|
||||
USB_DT_ENDPOINT, // bDescriptorType
|
||||
0x81, // bEndpointAddress
|
||||
USB_ENDPOINT_ATTR_INTERRUPT, // bmAttributes
|
||||
LSB(16), // wMaxPacketSize
|
||||
MSB(16), // wMaxPacketSize
|
||||
255, // bInterval
|
||||
|
||||
// interface descriptor, CDC
|
||||
USB_DT_INTERFACE_SIZE, // bLength
|
||||
USB_DT_INTERFACE, // bDescriptorType
|
||||
1, // bInterfaceNumber
|
||||
0, // bAlternateSetting
|
||||
2, // bNumEndpoints
|
||||
USB_CLASS_DATA, // bInterfaceClass
|
||||
0, // bInterfaceSubClass
|
||||
0, // bInterfaceProtocol
|
||||
0, // iInterface
|
||||
|
||||
// Endpoint descriptor
|
||||
USB_DT_ENDPOINT_SIZE, // bLength
|
||||
USB_DT_ENDPOINT, // bDescriptorType
|
||||
0x82, // bEndpointAddress
|
||||
USB_ENDPOINT_ATTR_BULK, // bmAttributes
|
||||
LSB(64), // wMaxPacketSize
|
||||
MSB(64), // wMaxPacketSize
|
||||
1, // bInterval
|
||||
|
||||
// Endpoint descriptor
|
||||
USB_DT_ENDPOINT_SIZE, // bLength
|
||||
USB_DT_ENDPOINT, // bDescriptorType
|
||||
0x02, // bEndpointAddress
|
||||
USB_ENDPOINT_ATTR_BULK, // bmAttributes
|
||||
LSB(64), // wMaxPacketSize
|
||||
MSB(64), // wMaxPacketSize
|
||||
1, // bInterval
|
||||
};
|
||||
|
||||
|
||||
// **************************************************************
|
||||
// String Descriptors
|
||||
// **************************************************************
|
||||
|
||||
// The descriptors above can provide human readable strings,
|
||||
// referenced by index numbers. These descriptors are the
|
||||
// actual string data
|
||||
|
||||
static const struct usb_string_descriptor_struct string0 = {
|
||||
4,
|
||||
3,
|
||||
{0x0409}
|
||||
};
|
||||
|
||||
__attribute__((aligned(4)))
|
||||
static const struct usb_string_descriptor_struct usb_string_manufacturer_name = {
|
||||
2 + MANUFACTURER_NAME_LEN,
|
||||
3,
|
||||
MANUFACTURER_NAME
|
||||
};
|
||||
|
||||
__attribute__((aligned(4)))
|
||||
static const struct usb_string_descriptor_struct usb_string_product_name = {
|
||||
2 + PRODUCT_NAME_LEN,
|
||||
3,
|
||||
PRODUCT_NAME
|
||||
};
|
||||
|
||||
// **************************************************************
|
||||
// Descriptors List
|
||||
// **************************************************************
|
||||
|
||||
// This table provides access to all the descriptor data above.
|
||||
|
||||
const usb_descriptor_list_t usb_descriptor_list[] = {
|
||||
{0x0100, sizeof(device_descriptor), device_descriptor},
|
||||
{0x0200, sizeof(config_descriptor), config_descriptor},
|
||||
{0x0300, 0, (const uint8_t *)&string0},
|
||||
{0x0301, 0, (const uint8_t *)&usb_string_manufacturer_name},
|
||||
{0x0302, 0, (const uint8_t *)&usb_string_product_name},
|
||||
{0, 0, NULL}
|
||||
};
|
254
sw/src/usb-epfifo.c
Normal file
254
sw/src/usb-epfifo.c
Normal file
@ -0,0 +1,254 @@
|
||||
#include <irq.h>
|
||||
#include <riscv.h>
|
||||
#include <string.h>
|
||||
#include <usb.h>
|
||||
|
||||
#ifdef CSR_USB_EP_0_OUT_EV_PENDING_ADDR
|
||||
|
||||
#define EP0OUT_BUFFERS 4
|
||||
__attribute__((aligned(4)))
|
||||
static uint8_t volatile usb_ep0out_buffer_len[EP0OUT_BUFFERS];
|
||||
static uint8_t volatile usb_ep0out_buffer[EP0OUT_BUFFERS][256];
|
||||
static uint8_t volatile usb_ep0out_last_tok[EP0OUT_BUFFERS];
|
||||
static volatile uint8_t usb_ep0out_wr_ptr;
|
||||
static volatile uint8_t usb_ep0out_rd_ptr;
|
||||
static const int max_byte_length = 64;
|
||||
|
||||
static const uint8_t * volatile current_data;
|
||||
static volatile int current_length;
|
||||
static volatile int data_offset;
|
||||
static volatile int data_to_send;
|
||||
static int next_packet_is_empty;
|
||||
|
||||
// Note that our PIDs are only bits 2 and 3 of the token,
|
||||
// since all other bits are effectively redundant at this point.
|
||||
enum USB_PID {
|
||||
USB_PID_OUT = 0,
|
||||
USB_PID_SOF = 1,
|
||||
USB_PID_IN = 2,
|
||||
USB_PID_SETUP = 3,
|
||||
};
|
||||
|
||||
enum epfifo_response {
|
||||
EPF_ACK = 0,
|
||||
EPF_NAK = 1,
|
||||
EPF_NONE = 2,
|
||||
EPF_STALL = 3,
|
||||
};
|
||||
|
||||
#define USB_EV_ERROR 1
|
||||
#define USB_EV_PACKET 2
|
||||
|
||||
void usb_idle(void) {
|
||||
usb_ep_0_out_ev_enable_write(0);
|
||||
usb_ep_0_in_ev_enable_write(0);
|
||||
|
||||
// Reject all incoming data, since there is no handler anymore
|
||||
usb_ep_0_out_respond_write(EPF_NAK);
|
||||
|
||||
// Reject outgoing data, since we don't have any to give.
|
||||
usb_ep_0_in_respond_write(EPF_NAK);
|
||||
|
||||
irq_setmask(irq_getmask() & ~(1 << USB_INTERRUPT));
|
||||
}
|
||||
|
||||
void usb_disconnect(void) {
|
||||
usb_ep_0_out_ev_enable_write(0);
|
||||
usb_ep_0_in_ev_enable_write(0);
|
||||
irq_setmask(irq_getmask() & ~(1 << USB_INTERRUPT));
|
||||
usb_pullup_out_write(0);
|
||||
}
|
||||
|
||||
void usb_connect(void) {
|
||||
|
||||
usb_ep_0_out_ev_pending_write(usb_ep_0_out_ev_enable_read());
|
||||
usb_ep_0_in_ev_pending_write(usb_ep_0_in_ev_pending_read());
|
||||
usb_ep_0_out_ev_enable_write(USB_EV_PACKET | USB_EV_ERROR);
|
||||
usb_ep_0_in_ev_enable_write(USB_EV_PACKET | USB_EV_ERROR);
|
||||
|
||||
// Accept incoming data by default.
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
|
||||
// Reject outgoing data, since we have none to give yet.
|
||||
usb_ep_0_in_respond_write(EPF_NAK);
|
||||
|
||||
usb_pullup_out_write(1);
|
||||
|
||||
irq_setmask(irq_getmask() | (1 << USB_INTERRUPT));
|
||||
}
|
||||
|
||||
void usb_init(void) {
|
||||
usb_ep0out_wr_ptr = 0;
|
||||
usb_ep0out_rd_ptr = 0;
|
||||
usb_pullup_out_write(0);
|
||||
return;
|
||||
}
|
||||
|
||||
static void process_tx(void) {
|
||||
|
||||
// Don't allow requeueing -- only queue more data if we're
|
||||
// currently set up to respond NAK.
|
||||
if (usb_ep_0_in_respond_read() != EPF_NAK) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent us from double-filling the buffer.
|
||||
if (!usb_ep_0_in_ibuf_empty_read()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!current_data || !current_length) {
|
||||
return;
|
||||
}
|
||||
|
||||
data_offset += data_to_send;
|
||||
|
||||
data_to_send = current_length - data_offset;
|
||||
|
||||
// Clamp the data to the maximum packet length
|
||||
if (data_to_send > max_byte_length) {
|
||||
data_to_send = max_byte_length;
|
||||
next_packet_is_empty = 0;
|
||||
}
|
||||
else if (data_to_send == max_byte_length) {
|
||||
next_packet_is_empty = 1;
|
||||
}
|
||||
else if (next_packet_is_empty) {
|
||||
next_packet_is_empty = 0;
|
||||
data_to_send = 0;
|
||||
}
|
||||
else if (current_data == NULL || data_to_send <= 0) {
|
||||
next_packet_is_empty = 0;
|
||||
current_data = NULL;
|
||||
current_length = 0;
|
||||
data_offset = 0;
|
||||
data_to_send = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int this_offset;
|
||||
for (this_offset = data_offset; this_offset < (data_offset + data_to_send); this_offset++) {
|
||||
usb_ep_0_in_ibuf_head_write(current_data[this_offset]);
|
||||
}
|
||||
usb_ep_0_in_respond_write(EPF_ACK);
|
||||
return;
|
||||
}
|
||||
|
||||
void usb_send(const void *data, int total_count) {
|
||||
|
||||
while ((current_length || current_data))// && usb_ep_0_in_respond_read() != EPF_NAK)
|
||||
;
|
||||
current_data = (uint8_t *)data;
|
||||
current_length = total_count;
|
||||
data_offset = 0;
|
||||
data_to_send = 0;
|
||||
process_tx();
|
||||
}
|
||||
|
||||
void usb_wait_for_send_done(void) {
|
||||
while (current_data && current_length)
|
||||
usb_poll();
|
||||
while ((usb_ep_0_in_dtb_read() & 1) == 1)
|
||||
usb_poll();
|
||||
}
|
||||
|
||||
void usb_isr(void) {
|
||||
uint8_t ep0o_pending = usb_ep_0_out_ev_pending_read();
|
||||
uint8_t ep0i_pending = usb_ep_0_in_ev_pending_read();
|
||||
|
||||
// We got an OUT or a SETUP packet. Copy it to usb_ep0out_buffer
|
||||
// and clear the "pending" bit.
|
||||
if (ep0o_pending) {
|
||||
uint8_t last_tok = usb_ep_0_out_last_tok_read();
|
||||
|
||||
int byte_count = 0;
|
||||
usb_ep0out_last_tok[usb_ep0out_wr_ptr] = last_tok;
|
||||
volatile uint8_t * obuf = usb_ep0out_buffer[usb_ep0out_wr_ptr];
|
||||
if (!usb_ep_0_out_obuf_empty_read()) {
|
||||
while (!usb_ep_0_out_obuf_empty_read()) {
|
||||
obuf[byte_count++] = usb_ep_0_out_obuf_head_read();
|
||||
usb_ep_0_out_obuf_head_write(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (byte_count >= 2)
|
||||
usb_ep0out_buffer_len[usb_ep0out_wr_ptr] = byte_count - 2 /* Strip off CRC16 */;
|
||||
usb_ep0out_wr_ptr = (usb_ep0out_wr_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
|
||||
if (last_tok == USB_PID_SETUP) {
|
||||
usb_ep_0_in_dtb_write(1);
|
||||
data_offset = 0;
|
||||
current_length = 0;
|
||||
current_data = NULL;
|
||||
}
|
||||
|
||||
usb_ep_0_out_ev_pending_write(ep0o_pending);
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
}
|
||||
|
||||
// We just got an "IN" token. Send data if we have it.
|
||||
if (ep0i_pending) {
|
||||
usb_ep_0_in_respond_write(EPF_NAK);
|
||||
usb_ep_0_in_ev_pending_write(ep0i_pending);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void usb_ack_in(void) {
|
||||
while (usb_ep_0_in_respond_read() == EPF_ACK)
|
||||
;
|
||||
usb_ep_0_in_respond_write(EPF_ACK);
|
||||
}
|
||||
|
||||
void usb_ack_out(void) {
|
||||
while (usb_ep_0_out_respond_read() == EPF_ACK)
|
||||
;
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
}
|
||||
|
||||
void usb_err(void) {
|
||||
usb_ep_0_out_respond_write(EPF_STALL);
|
||||
usb_ep_0_in_respond_write(EPF_STALL);
|
||||
}
|
||||
|
||||
int usb_recv(void *buffer, unsigned int buffer_len) {
|
||||
|
||||
// Set the OUT response to ACK, since we are in a position to receive data now.
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
while (1) {
|
||||
if (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
|
||||
if (usb_ep0out_last_tok[usb_ep0out_rd_ptr] == USB_PID_OUT) {
|
||||
unsigned int ep0_buffer_len = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
|
||||
if (ep0_buffer_len < buffer_len)
|
||||
buffer_len = ep0_buffer_len;
|
||||
// usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
|
||||
memcpy(buffer, (void *)&usb_ep0out_buffer[usb_ep0out_rd_ptr], buffer_len);
|
||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
return buffer_len;
|
||||
}
|
||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usb_poll(void) {
|
||||
// If some data was received, then process it.
|
||||
while (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
|
||||
const struct usb_setup_request *request = (const struct usb_setup_request *)(usb_ep0out_buffer[usb_ep0out_rd_ptr]);
|
||||
// uint8_t len = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
|
||||
uint8_t last_tok = usb_ep0out_last_tok[usb_ep0out_rd_ptr];
|
||||
|
||||
// usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
|
||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
|
||||
if (last_tok == USB_PID_SETUP) {
|
||||
usb_setup(request);
|
||||
}
|
||||
}
|
||||
|
||||
process_tx();
|
||||
}
|
||||
|
||||
#endif /* CSR_USB_EP_0_OUT_EV_PENDING_ADDR */
|
114
sw/src/usb-setup.c
Normal file
114
sw/src/usb-setup.c
Normal file
@ -0,0 +1,114 @@
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <usb.h>
|
||||
|
||||
#include <usb-desc.h>
|
||||
|
||||
static uint8_t reply_buffer[8];
|
||||
static uint8_t usb_configuration = 0;
|
||||
|
||||
void usb_setup(const struct usb_setup_request *setup)
|
||||
{
|
||||
const uint8_t *data = NULL;
|
||||
uint32_t datalen = 0;
|
||||
const usb_descriptor_list_t *list;
|
||||
|
||||
switch (setup->wRequestAndType)
|
||||
{
|
||||
case 0x0500: // SET_ADDRESS
|
||||
case 0x0b01: // SET_INTERFACE
|
||||
break;
|
||||
|
||||
case 0x0900: // SET_CONFIGURATION
|
||||
usb_configuration = setup->wValue;
|
||||
break;
|
||||
|
||||
case 0x0880: // GET_CONFIGURATION
|
||||
reply_buffer[0] = usb_configuration;
|
||||
datalen = 1;
|
||||
data = reply_buffer;
|
||||
break;
|
||||
|
||||
case 0x0080: // GET_STATUS (device)
|
||||
reply_buffer[0] = 0;
|
||||
reply_buffer[1] = 0;
|
||||
datalen = 2;
|
||||
data = reply_buffer;
|
||||
break;
|
||||
|
||||
case 0x0082: // GET_STATUS (endpoint)
|
||||
if (setup->wIndex > 0)
|
||||
{
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
reply_buffer[0] = 0;
|
||||
reply_buffer[1] = 0;
|
||||
|
||||
// XXX handle endpoint stall here
|
||||
data = reply_buffer;
|
||||
datalen = 2;
|
||||
break;
|
||||
|
||||
case 0x0102: // CLEAR_FEATURE (endpoint)
|
||||
if (setup->wIndex > 0 || setup->wValue != 0)
|
||||
{
|
||||
// TODO: do we need to handle IN vs OUT here?
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0302: // SET_FEATURE (endpoint)
|
||||
if (setup->wIndex > 0 || setup->wValue != 0)
|
||||
{
|
||||
// TODO: do we need to handle IN vs OUT here?
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
// XXX: Should we set the stall bit?
|
||||
// USB->DIEP0CTL |= USB_DIEP_CTL_STALL;
|
||||
// TODO: do we need to clear the data toggle here?
|
||||
break;
|
||||
|
||||
case 0x0680: // GET_DESCRIPTOR
|
||||
case 0x0681:
|
||||
for (list = usb_descriptor_list; 1; list++)
|
||||
{
|
||||
if (list->addr == NULL)
|
||||
break;
|
||||
if (setup->wValue == list->wValue)
|
||||
{
|
||||
data = list->addr;
|
||||
if ((setup->wValue >> 8) == 3)
|
||||
{
|
||||
// for string descriptors, use the descriptor's
|
||||
// length field, allowing runtime configured
|
||||
// length.
|
||||
datalen = *(list->addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
datalen = list->length;
|
||||
}
|
||||
goto send;
|
||||
}
|
||||
}
|
||||
usb_err();
|
||||
return;
|
||||
|
||||
default:
|
||||
usb_err();
|
||||
return;
|
||||
}
|
||||
|
||||
send:
|
||||
if (data && datalen) {
|
||||
if (datalen > setup->wLength)
|
||||
datalen = setup->wLength;
|
||||
usb_send(data, datalen);
|
||||
}
|
||||
else
|
||||
usb_ack_in();
|
||||
return;
|
||||
}
|
Loading…
Reference in New Issue
Block a user