Merge pull request #28 from zakgi/master

Adding initial support for Saanlima's Pipistrello LX45 board
This commit is contained in:
enjoy-digital 2019-12-31 17:33:25 +01:00 committed by GitHub
commit 6324433e1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 402 additions and 0 deletions

View File

@ -0,0 +1,170 @@
from litex.build.generic_platform import *
from litex.build.xilinx import XilinxPlatform
from litex.build.xilinx.programmer import XC3SProg
from litex.build.openocd import OpenOCD
_io = [
("user_led", 0, Pins("V16"), IOStandard("LVTTL"), Drive(8), Misc("SLEW=QUIETIO")), # green at hdmi
("user_led", 1, Pins("U16"), IOStandard("LVTTL"), Drive(8), Misc("SLEW=QUIETIO")), # red at hdmi
("user_led", 2, Pins("A16"), IOStandard("LVTTL"), Drive(8), Misc("SLEW=QUIETIO")), # green at msd
("user_led", 3, Pins("A15"), IOStandard("LVTTL"), Drive(8), Misc("SLEW=QUIETIO")), # red at msd
("user_led", 4, Pins("A12"), IOStandard("LVTTL"), Drive(8), Misc("SLEW=QUIETIO")), # red at usb
("user_btn", 0, Pins("N14"), IOStandard("LVTTL"), Misc("PULLDOWN")),
("clk50", 0, Pins("H17"), IOStandard("LVTTL")),
("serial", 0,
Subsignal("tx", Pins("A10")),
Subsignal("rx", Pins("A11"), Misc("PULLUP")),
Subsignal("cts", Pins("C10"), Misc("PULLUP")),
Subsignal("rts", Pins("A9"), Misc("PULLUP")),
IOStandard("LVTTL"),
),
("usb_fifo", 0,
Subsignal("data", Pins("A11 A10 C10 A9 B9 A8 B8 A7")),
Subsignal("rxf_n", Pins("C7")),
Subsignal("txe_n", Pins("A6")),
Subsignal("rd_n", Pins("B6")),
Subsignal("wr_n", Pins("A5")),
Subsignal("siwua", Pins("C5")),
IOStandard("LVTTL"),
),
("hdmi", 0,
Subsignal("clk_p", Pins("U5"), IOStandard("TMDS_33")),
Subsignal("clk_n", Pins("V5"), IOStandard("TMDS_33")),
Subsignal("data0_p", Pins("T6"), IOStandard("TMDS_33")),
Subsignal("data0_n", Pins("V6"), IOStandard("TMDS_33")),
Subsignal("data1_p", Pins("U7"), IOStandard("TMDS_33")),
Subsignal("data1_n", Pins("V7"), IOStandard("TMDS_33")),
Subsignal("data2_p", Pins("U8"), IOStandard("TMDS_33")),
Subsignal("data2_n", Pins("V8"), IOStandard("TMDS_33")),
Subsignal("scl", Pins("V9"), IOStandard("I2C")),
Subsignal("sda", Pins("T9"), IOStandard("I2C")),
Subsignal("hpd_notif", Pins("R8"), IOStandard("LVTTL")),
),
("spiflash", 0,
Subsignal("cs_n", Pins("V3")),
Subsignal("clk", Pins("R15")),
Subsignal("mosi", Pins("T13")),
Subsignal("miso", Pins("R13"), Misc("PULLUP")),
Subsignal("wp", Pins("T14")),
Subsignal("hold", Pins("V14")),
IOStandard("LVTTL"), Misc("SLEW=FAST")
),
("spiflash2x", 0,
Subsignal("cs_n", Pins("V3")),
Subsignal("clk", Pins("R15")),
Subsignal("dq", Pins("T13 R13"), Misc("PULLUP")),
Subsignal("wp", Pins("T14")),
Subsignal("hold", Pins("V14")),
IOStandard("LVTTL"), Misc("SLEW=FAST")
),
("spiflash4x", 0,
Subsignal("cs_n", Pins("V3")),
Subsignal("clk", Pins("R15")),
Subsignal("dq", Pins("T13 R13 T14 V14"), Misc("PULLUP")),
IOStandard("LVTTL"), Misc("SLEW=FAST")
),
("mmc", 0,
Subsignal("clk", Pins("A3")),
Subsignal("cmd", Pins("B3"), Misc("PULLUP")),
Subsignal("dat", Pins("B4 A4 B2 A2"), Misc("PULLUP")),
IOStandard("SDIO")
),
("mmc_spi", 0,
Subsignal("cs_n", Pins("A2"), Misc("PULLUP")),
Subsignal("clk", Pins("A3")),
Subsignal("mosi", Pins("B3")),
Subsignal("miso", Pins("B4"), Misc("PULLUP")),
IOStandard("SDIO")
),
("audio", 0,
Subsignal("l", Pins("R7"), Misc("SLEW=SLOW")),
Subsignal("r", Pins("T7"), Misc("SLEW=SLOW")),
IOStandard("LVTTL"),
),
("pmod", 0,
Subsignal("d", Pins("D9 C8 D6 C4 B11 C9 D8 C6")),
IOStandard("LVTTL")
),
("ddram_clock", 0,
Subsignal("p", Pins("G3")),
Subsignal("n", Pins("G1")),
IOStandard("MOBILE_DDR")
),
("ddram", 0,
Subsignal("a", Pins("J7 J6 H5 L7 F3 H4 H3 H6 D2 D1 F4 D3 G6")),
Subsignal("ba", Pins("F2 F1")),
Subsignal("cke", Pins("H7")),
Subsignal("ras_n", Pins("L5")),
Subsignal("cas_n", Pins("K5")),
Subsignal("we_n", Pins("E3")),
Subsignal("dq", Pins("L2 L1 K2 K1 H2 H1 J3 J1 M3 M1 N2 N1 T2 T1 U2 U1")),
Subsignal("dqs", Pins("L4 P2")),
Subsignal("dm", Pins("K3 K4")),
IOStandard("MOBILE_DDR")
)
]
_connectors = [
("A", "U18 T17 P17 P16 N16 N17 M16 L15 L17 K15 K17 J16 H15 H18 F18 D18"),
("B", "C18 E18 G18 H16 J18 K18 K16 L18 L16 M18 N18 N15 P15 P18 T18 U17"),
("C", "F17 F16 E16 G16 F15 G14 F14 H14 H13 J13 G13 H12 K14 K13 K12 L12"),
]
_hdmi_infos = {
"HDMI_OUT0_MNEMONIC": "J4",
"HDMI_OUT0_DESCRIPTION" : (
" Type A connector, marked as J4.\\r\\n"
)
}
class Platform(XilinxPlatform):
name = "pipistrello"
identifier = 0x5049
default_clk_name = "clk50"
default_clk_period = 20
hdmi_infos = _hdmi_infos
# Micron N25Q128 (ID 0x0018ba20)
# FIXME: Create a "spi flash module" object in the same way we have SDRAM
# module objects.
spiflash_model = "n25q128"
spiflash_read_dummy_bits = 10
spiflash_clock_div = 4
spiflash_total_size = int((128/8)*1024*1024) # 128Mbit
spiflash_page_size = 256
spiflash_sector_size = 0x10000
# The Pipistrello has a XC6SLX45 which bitstream takes up ~12Mbit (1484472 bytes)
# 0x200000 offset (16Mbit) gives plenty of space
gateware_size = 0x200000
def __init__(self, programmer="openocd"):
XilinxPlatform.__init__(self, "xc6slx45-csg324-3", _io, _connectors)
self.toolchain.bitgen_opt += " -g Compress -g ConfigRate:6"
self.programmer = programmer
def create_programmer(self):
proxy="bscan_spi_{}.bit".format(self.device.split('-')[0])
if self.programmer == "openocd":
return OpenOCD(config="board/pipistrello.cfg", flash_proxy_basename=proxy)
# Alternative programmers - not regularly tested.
elif self.programmer == "xc3sprog":
return XC3SProg("papilio", "bscan_spi_lx45_csg324.bit")
else:
raise ValueError("{} programmer is not supported".format(self.programmer))

View File

@ -0,0 +1,232 @@
#!/usr/bin/env python3
from fractions import Fraction
from migen import *
from migen.genlib.resetsync import AsyncResetSynchronizer
from litex_boards.platforms import pipistrello
from litex.soc.integration.soc_sdram import *
from litex.soc.integration.builder import *
from litedram.modules import MT46H32M16
from litedram.phy import s6ddrphy
from litedram.core import ControllerSettings
import argparse
class _CRG(Module):
def __init__(self, platform, clk_freq):
# Clock domains for the system (soft CPU and related components run at).
self.clock_domains.cd_sys = ClockDomain()
# Clock domains for the DDR interface.
self.clock_domains.cd_sdram_half = ClockDomain()
self.clock_domains.cd_sdram_full_wr = ClockDomain()
self.clock_domains.cd_sdram_full_rd = ClockDomain()
# Clock domain for peripherals (such as HDMI output).
self.clock_domains.cd_base50 = ClockDomain()
self.reset = Signal()
# Input 50MHz clock
f0 = 50*1000000
clk50 = platform.request("clk50")
clk50a = Signal()
# Input 50MHz clock (buffered)
#self.specials += Instance("IBUFG", i_I=clk50, o_O=clk50a)
clk50b = Signal()
self.specials += Instance(
"BUFIO2", p_DIVIDE=1,
p_DIVIDE_BYPASS="TRUE", p_I_INVERT="FALSE",
i_I=clk50, o_DIVCLK=clk50b)
p = 12
f = Fraction(clk_freq*p, f0)
n, d = f.numerator, f.denominator
assert 19e6 <= f0/d <= 500e6 # pfd
assert 400e6 <= f0*n/d <= 1080e6 # vco
# Unbuffered output signals from the PLL. They need to be buffered
# before feeding into the fabric.
unbuf_sdram_full = Signal()
unbuf_sdram_half_a = Signal()
unbuf_sdram_half_b = Signal()
unbuf_unused = Signal()
unbuf_sys = Signal()
unbuf_periph = Signal()
# PLL signals
pll_lckd = Signal()
pll_fb = Signal()
self.specials.pll = Instance(
"PLL_ADV",
name="crg_pll_adv",
p_SIM_DEVICE="SPARTAN6", p_BANDWIDTH="OPTIMIZED", p_COMPENSATION="INTERNAL",
p_REF_JITTER=.01,
i_DADDR=0, i_DCLK=0, i_DEN=0, i_DI=0, i_DWE=0, i_RST=0, i_REL=0,
p_DIVCLK_DIVIDE=d,
# Input Clocks (50MHz)
i_CLKIN1=clk50b,
p_CLKIN1_PERIOD=1e9/f0,
i_CLKIN2=0,
p_CLKIN2_PERIOD=0.,
i_CLKINSEL=1,
# Feedback
i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, o_LOCKED=pll_lckd,
p_CLK_FEEDBACK="CLKFBOUT",
p_CLKFBOUT_MULT=n, p_CLKFBOUT_PHASE=0.,
# (333MHz) sdram wr rd
o_CLKOUT0=unbuf_sdram_full, p_CLKOUT0_DUTY_CYCLE=.5,
p_CLKOUT0_PHASE=0., p_CLKOUT0_DIVIDE=p//4,
# unused?
o_CLKOUT1=unbuf_unused, p_CLKOUT1_DUTY_CYCLE=.5,
p_CLKOUT1_PHASE=0., p_CLKOUT1_DIVIDE=15,
# (166MHz) sdram_half - sdram dqs adr ctrl
o_CLKOUT2=unbuf_sdram_half_a, p_CLKOUT2_DUTY_CYCLE=.5,
p_CLKOUT2_PHASE=270., p_CLKOUT2_DIVIDE=p//2,
# (166MHz) off-chip ddr
o_CLKOUT3=unbuf_sdram_half_b, p_CLKOUT3_DUTY_CYCLE=.5,
p_CLKOUT3_PHASE=250., p_CLKOUT3_DIVIDE=p//2,
# ( 50MHz) periph
o_CLKOUT4=unbuf_periph, p_CLKOUT4_DUTY_CYCLE=.5,
p_CLKOUT4_PHASE=0., p_CLKOUT4_DIVIDE=20,
# ( 83MHz) sysclk
o_CLKOUT5=unbuf_sys, p_CLKOUT5_DUTY_CYCLE=.5,
p_CLKOUT5_PHASE=0., p_CLKOUT5_DIVIDE=p//1,
)
# power on reset?
reset = platform.request("user_btn") | self.reset
self.clock_domains.cd_por = ClockDomain()
por = Signal(max=1 << 11, reset=(1 << 11) - 1)
self.sync.por += If(por != 0, por.eq(por - 1))
self.specials += AsyncResetSynchronizer(self.cd_por, reset)
# System clock - 83MHz
self.specials += Instance("BUFG", i_I=unbuf_sys, o_O=self.cd_sys.clk)
self.comb += self.cd_por.clk.eq(self.cd_sys.clk)
self.specials += AsyncResetSynchronizer(self.cd_sys, ~pll_lckd | (por > 0))
# SDRAM clocks
# ------------------------------------------------------------------------------
self.clk4x_wr_strb = Signal()
self.clk4x_rd_strb = Signal()
# sdram_full
self.specials += Instance("BUFPLL", name="sdram_full_bufpll",
p_DIVIDE=4,
i_PLLIN=unbuf_sdram_full, i_GCLK=self.cd_sys.clk,
i_LOCKED=pll_lckd,
o_IOCLK=self.cd_sdram_full_wr.clk,
o_SERDESSTROBE=self.clk4x_wr_strb)
self.comb += [
self.cd_sdram_full_rd.clk.eq(self.cd_sdram_full_wr.clk),
self.clk4x_rd_strb.eq(self.clk4x_wr_strb),
]
# sdram_half
self.specials += Instance("BUFG", name="sdram_half_a_bufpll", i_I=unbuf_sdram_half_a, o_O=self.cd_sdram_half.clk)
clk_sdram_half_shifted = Signal()
self.specials += Instance("BUFG", name="sdram_half_b_bufpll", i_I=unbuf_sdram_half_b, o_O=clk_sdram_half_shifted)
clk = platform.request("ddram_clock")
self.specials += Instance("ODDR2", p_DDR_ALIGNMENT="NONE",
p_INIT=0, p_SRTYPE="SYNC",
i_D0=1, i_D1=0, i_S=0, i_R=0, i_CE=1,
i_C0=clk_sdram_half_shifted,
i_C1=~clk_sdram_half_shifted,
o_Q=clk.p)
self.specials += Instance("ODDR2", p_DDR_ALIGNMENT="NONE",
p_INIT=0, p_SRTYPE="SYNC",
i_D0=0, i_D1=1, i_S=0, i_R=0, i_CE=1,
i_C0=clk_sdram_half_shifted, i_C1=~clk_sdram_half_shifted,
o_Q=clk.n)
# Peripheral clock - 50MHz
# ------------------------------------------------------------------------------
# The peripheral clock is kept separate from the system clock to allow
# the system clock to be increased in the future.
dcm_base50_locked = Signal()
self.specials += [
Instance("DCM_CLKGEN", name="crg_periph_dcm_clkgen",
p_CLKIN_PERIOD=20.0,
p_CLKFX_MULTIPLY=2,
p_CLKFX_DIVIDE=2,
p_CLKFX_MD_MAX=1.0, # CLKFX_MULTIPLY/CLKFX_DIVIDE
p_CLKFXDV_DIVIDE=2,
p_SPREAD_SPECTRUM="NONE",
p_STARTUP_WAIT="FALSE",
i_CLKIN=clk50a,
o_CLKFX=self.cd_base50.clk,
o_LOCKED=dcm_base50_locked,
i_FREEZEDCM=0,
i_RST=ResetSignal(),
),
AsyncResetSynchronizer(self.cd_base50,
self.cd_sys.rst | ~dcm_base50_locked)
]
platform.add_period_constraint(self.cd_base50.clk, 20)
class BaseSoC(SoCSDRAM):
mem_map = {
"spiflash": 0x20000000, # (default shadow @0xa0000000)
}
mem_map.update(SoCSDRAM.mem_map)
def __init__(self, **kwargs):
if 'integrated_rom_size' not in kwargs:
kwargs['integrated_rom_size']=0x8000
if 'integrated_sram_size' not in kwargs:
kwargs['integrated_sram_size']=0x8000
clk_freq = (83 + Fraction(1, 3))*1000*1000
platform = pipistrello.Platform()
SoCSDRAM.__init__(self, platform, clk_freq, **kwargs)
self.submodules.crg = _CRG(platform, clk_freq)
self.platform.add_period_constraint(self.crg.cd_sys.clk, 1e9/clk_freq)
bios_size = 0x8000
# sdram
sdram_module = MT46H32M16(self.clk_freq, "1:2")
self.submodules.ddrphy = s6ddrphy.S6HalfRateDDRPHY(
platform.request("ddram"),
sdram_module.memtype,
rd_bitslip=1,
wr_bitslip=3,
dqs_ddr_alignment="C1")
self.add_csr("ddrphy")
controller_settings = ControllerSettings(with_bandwidth=True)
self.register_sdram(self.ddrphy,
sdram_module.geom_settings,
sdram_module.timing_settings,
controller_settings=controller_settings)
self.comb += [
self.ddrphy.clk4x_wr_strb.eq(self.crg.clk4x_wr_strb),
self.ddrphy.clk4x_rd_strb.eq(self.crg.clk4x_rd_strb),
]
# Build --------------------------------------------------------------------------------------------
def main():
parser = argparse.ArgumentParser(description="LiteX SoC on Pipistrello")
builder_args(parser)
soc_sdram_args(parser)
args = parser.parse_args()
soc = BaseSoC(**soc_sdram_argdict(args))
builder = Builder(soc, **builder_argdict(args))
builder.build()
if __name__ == "__main__":
main()