Skip to content

Commit ef2f911

Browse files
committed
Initial public release
Signed-off-by: Michael Neuling <[email protected]> Signed-off-by: Anton Blanchard <[email protected]>
0 parents  commit ef2f911

26 files changed

+2919
-0
lines changed

.gitignore

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Python
2+
__pycache__/
3+
/*.egg-info
4+
/.eggs
5+
/dist
6+
7+
# tests
8+
*.v
9+
*.vcd
10+
*.gtkw

LICENSE

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
© IBM Corp. 2021
2+
3+
Licensed under the Apache License, Version 2.0 (the "License"), as modified by
4+
the terms below; you may not use the files in this repository except in
5+
compliance with the License as modified. You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
8+
Modified Terms:
9+
1) For the purpose of the patent license granted to you in Section 3 of
10+
the License, the "Work" hereby includes implementations of the work of
11+
authorship in physical form.
12+
13+
Unless required by applicable law or agreed to in writing, the reference design
14+
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15+
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16+
License for the specific language governing permissions and limitations under
17+
the License.
18+
19+
Brief explanation of modifications:
20+
21+
Modification 1: This modification extends the patent license to an
22+
implementation of the Work in physical form – i.e.,it unambiguously permits a
23+
user to make and use the physical chip.

README.md

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# LPC Peripheral Overview
2+
3+
This is an LPC peripheral that implements LPC IO and FW cycles so that
4+
it can boot a host like a POWER9. This peripheral would typically sit
5+
inside a BMC SoC.
6+
7+
# System diagram
8+
```
9+
.
10+
.
11+
LPC LPC Clock . System Clock
12+
pins . LPC FW DMA
13+
+---------+ +------------+ +--------+ Wishbone +--------+ Wishbone
14+
| | | ASYNC | | | | LPC | Master
15+
LCLK | +---->| FIFO WR +---->| +--------->| CTRL +-------->
16+
------->| LPC | | | | | | |
17+
| Front | +------------+ | LOGIC | +--------+
18+
LFRAME | | . | |
19+
------->| | +------------+ | | +--------+
20+
| | | ASYNC | | | | IPMI BT|
21+
LAD | |<----+ FIFO RD |<----+ +--------->| FIFO |<--------
22+
<------>| | | | | | | | IO
23+
+---------+ +------------+ +--------+ LPC IO +--------+ Wishbone
24+
. Wishbone | UART | Slave
25+
. | |
26+
. +--------+
27+
. | CTRL |
28+
| |
29+
+--------+
30+
```
31+
32+
The design translates the LPC IO accesses into a wishbone master. The
33+
same is done for FW accesses.
34+
35+
The LPC IO wishbone master bus has devices attached to it. These
36+
include a an IPMI BT FIFO and standard 16550 UART. The back end of
37+
these can then be access by an external IO wishbone slave (which would
38+
typically come from the BMC CPU).
39+
40+
The LPC FW wishbone master gets translated into an external wishbone
41+
master. This translation provides an offset and mask so the external
42+
wishbone master accesses occur can be controlled. Typically this
43+
external wishbone will be hooked into a DMA path the system bus of the
44+
BMC, so where this can access needs to be controlled.
45+
46+
The LPC front end runs using the LPC clock. The rest of the design
47+
works on the normal system clock. Async FIFOs provide a safe boundary
48+
between the two.
49+
50+
HDL is written in nmigen because that's what all the cool kids are
51+
doing. This is our first nmigen project, and we are software
52+
developers, so be kind!
53+
54+
# Building
55+
56+
This is designed to be integrated into some other project (like
57+
microwatt for libreBMC) not build as a standalone project.
58+
59+
If you want the verilog, do this to produce a lpcperipheral.v
60+
```
61+
python -m lpcperipheral.lpcperipheral
62+
```
63+
64+
# Testing
65+
66+
There are an extensive set of tests in tests/. To run these do:
67+
68+
```
69+
python -m unittest
70+
```

lpcperipheral/__init__.py

Whitespace-only changes.

lpcperipheral/io_space.py

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
from nmigen import Elaboratable, Module, Signal
2+
from nmigen.back import verilog
3+
from nmigen_soc.wishbone import Decoder as WishboneDecoder
4+
from nmigen_soc.wishbone import Interface as WishboneInterface
5+
from nmigen_soc.memory import MemoryMap
6+
7+
from .ipmi_bt import IPMI_BT
8+
from .vuart_joined import VUartJoined
9+
10+
11+
class IOSpace(Elaboratable):
12+
def __init__(self, vuart_depth=2048, bmc_vuart_addr=0x0, bmc_ipmi_addr=0x1000,
13+
bmc_lpc_ctrl_addr=0x2000,
14+
target_vuart_addr=0x3f8, target_ipmi_addr=0xe4):
15+
self.vuart_depth = vuart_depth
16+
# BMC wishbone is 32 bit wide, so divide addresses by 4
17+
self.bmc_vuart_addr = bmc_vuart_addr // 4
18+
self.bmc_ipmi_addr = bmc_ipmi_addr // 4
19+
self.bmc_lpc_ctrl_addr = bmc_lpc_ctrl_addr // 4
20+
self.target_vuart_addr = target_vuart_addr
21+
self.target_ipmi_addr = target_ipmi_addr
22+
23+
self.bmc_vuart_irq = Signal()
24+
self.bmc_ipmi_irq = Signal()
25+
self.bmc_wb = WishboneInterface(addr_width=14, data_width=8)
26+
27+
self.target_vuart_irq = Signal()
28+
self.target_ipmi_irq = Signal()
29+
self.target_wb = WishboneInterface(addr_width=16, data_width=8, features=["err"])
30+
31+
self.lpc_ctrl_wb = WishboneInterface(addr_width=3, data_width=8)
32+
33+
self.error_wb = WishboneInterface(addr_width=2, data_width=8,
34+
features=["err"])
35+
36+
def elaborate(self, platform):
37+
m = Module()
38+
39+
m.submodules.vuart_joined = vuart_joined = VUartJoined(depth=self.vuart_depth)
40+
m.submodules.ipmi_bt = ipmi_bt = IPMI_BT()
41+
42+
# BMC address decode
43+
m.submodules.bmc_decode = bmc_decode = WishboneDecoder(addr_width=14, data_width=8, granularity=8)
44+
45+
bmc_ipmi_bus = ipmi_bt.bmc_wb
46+
bmc_ipmi_bus.memory_map = MemoryMap(addr_width=3, data_width=8)
47+
bmc_decode.add(bmc_ipmi_bus, addr=self.bmc_ipmi_addr)
48+
49+
bmc_vuart_bus = vuart_joined.wb_a
50+
bmc_vuart_bus.memory_map = MemoryMap(addr_width=3, data_width=8)
51+
bmc_decode.add(bmc_vuart_bus, addr=self.bmc_vuart_addr)
52+
53+
lpc_ctrl_bus = self.lpc_ctrl_wb
54+
lpc_ctrl_bus.memory_map = MemoryMap(addr_width=3, data_width=8)
55+
bmc_decode.add(lpc_ctrl_bus, addr=self.bmc_lpc_ctrl_addr)
56+
57+
m.d.comb += [
58+
self.bmc_ipmi_irq.eq(ipmi_bt.bmc_irq),
59+
self.bmc_vuart_irq.eq(vuart_joined.irq_a),
60+
self.bmc_wb.connect(bmc_decode.bus)
61+
]
62+
63+
# Target address decode
64+
m.submodules.target_decode = target_decode = WishboneDecoder(addr_width=16, data_width=8, granularity=8, features=["err"])
65+
66+
target_ipmi_bus = ipmi_bt.target_wb
67+
target_ipmi_bus.memory_map = MemoryMap(addr_width=2, data_width=8)
68+
target_decode.add(target_ipmi_bus, addr=self.target_ipmi_addr)
69+
70+
target_vuart_bus = vuart_joined.wb_b
71+
target_vuart_bus.memory_map = MemoryMap(addr_width=3, data_width=8)
72+
target_decode.add(target_vuart_bus, addr=self.target_vuart_addr)
73+
74+
target_error_bus = self.error_wb
75+
target_error_bus.memory_map = MemoryMap(addr_width=2, data_width=8)
76+
# Generate a signal when we'd expect an ACK on the target bus
77+
ack_expected = Signal()
78+
m.d.sync += ack_expected.eq(self.target_wb.sel & self.target_wb.cyc &
79+
~ack_expected)
80+
# Generate an error if no ack from ipmi_bt or vuart
81+
m.d.comb += self.error_wb.err.eq(0)
82+
with m.If (ack_expected):
83+
m.d.comb += self.error_wb.err.eq(~ipmi_bt.target_wb.ack &
84+
~vuart_joined.wb_b.ack)
85+
target_decode.add(target_error_bus, addr=0x0)
86+
87+
m.d.comb += [
88+
self.target_ipmi_irq.eq(ipmi_bt.target_irq),
89+
self.target_vuart_irq.eq(vuart_joined.irq_b),
90+
self.target_wb.connect(target_decode.bus)
91+
]
92+
93+
return m
94+
95+
96+
if __name__ == "__main__":
97+
top = IOSpace()
98+
with open("io_map.v", "w") as f:
99+
f.write(verilog.convert(top))

0 commit comments

Comments
 (0)