diff --git a/litex_boards/platforms/logicbone.py b/litex_boards/platforms/logicbone.py
new file mode 100644
index 0000000000000000000000000000000000000000..c1cfc932ed2e5e32759fd08c59fd7ba6dbb2140c
--- /dev/null
+++ b/litex_boards/platforms/logicbone.py
@@ -0,0 +1,195 @@
+# This file is Copyright (c) 2020 Owen Kirby <oskirby@gmail.com>
+# License: BSD
+#
+# Logicbone ECP5:
+# - Design files: https://github.com/oskirby/logicbone
+# - Bootloader: https://github.com/oskirby/tinydfu-bootloader
+#
+
+from litex.build.generic_platform import *
+from litex.build.lattice import LatticePlatform
+from litex.build.dfu import DFUProg
+
+# IOs ----------------------------------------------------------------------------------------------
+
+_io_rev0 = [
+    ("refclk", 0, Pins("M19"),  IOStandard("LVCMOS18")),
+    ("rst_n", 0, Pins("C17"), IOStandard("LVCMOS33")),
+    ("user_btn", 0, Pins("U2"), IOStandard("LVCMOS33")),
+
+    ("user_led", 0, Pins("D16"), IOStandard("LVCMOS33")),
+    ("user_led", 1, Pins("C15"), IOStandard("LVCMOS33")),
+    ("user_led", 2, Pins("C13"), IOStandard("LVCMOS33")),
+    ("user_led", 3, Pins("B13"), IOStandard("LVCMOS33")),
+
+    ("ddram", 0,
+        Subsignal("a", Pins(
+            "D5 F4 B3 F3 E5 C3 C4 A5",
+            "A3 B5 G3 F5 D2 A4 D3 E3"),
+            IOStandard("SSTL135_I")),
+        Subsignal("ba",    Pins("B4 H5 N2"), IOStandard("SSTL135_I")),
+        Subsignal("ras_n", Pins("L1"), IOStandard("SSTL135_I")),
+        Subsignal("cas_n", Pins("M1"), IOStandard("SSTL135_I")),
+        Subsignal("we_n",  Pins("E4"), IOStandard("SSTL135_I")),
+        Subsignal("cs_n",  Pins("M3"), IOStandard("SSTL135_I")), 
+        #Subsignal("dm", Pins("L4 J5"), IOStandard("SSTL135_I")),
+        Subsignal("dm", Pins("L5 H3"), IOStandard("SSTL135_I")), # HACK: I broke the DM pins, so we'll use some NC pins instead.
+        Subsignal("dq", Pins(
+            "G2 K1 F1 K3 H2 J3 G1 H1",
+            "B1 E1 A2 F2 C1 E2 C2 D1"),
+            IOStandard("SSTL135_I"),
+            Misc("TERMINATION=75")),
+        Subsignal("dqs_p", Pins("K2 H4"), IOStandard("SSTL135D_I"),
+            Misc("TERMINATION=OFF"),
+            Misc("DIFFRESISTOR=100")),
+        Subsignal("clk_p", Pins("M4"), IOStandard("SSTL135D_I")),
+        Subsignal("cke",   Pins("K4"), IOStandard("SSTL135_I")),
+        Subsignal("odt",   Pins("C5"), IOStandard("SSTL135_I")),
+        Subsignal("reset_n", Pins("P1"), IOStandard("SSTL135_I")),
+        Misc("SLEWRATE=FAST"),
+    ),
+
+    ("usb", 0,
+        Subsignal("d_p", Pins("B12")),
+        Subsignal("d_n", Pins("C12")),
+        Subsignal("pullup", Pins("C16")),
+        IOStandard("LVCMOS33")
+    ),
+
+    ("serial", 0,
+        Subsignal("rx", Pins("B6"), IOStandard("LVCMOS33")),
+        Subsignal("tx", Pins("A7"), IOStandard("LVCMOS33")),
+    ),
+
+    ("spiflash4x", 0,
+        Subsignal("cs_n", Pins("R2"), IOStandard("LVCMOS33")),
+        #Subsignal("clk",  Pins("U3"), IOStandard("LVCMOS33")), # Note: CLK is bound using USRMCLK block
+        Subsignal("dq",   Pins("W2 V2 Y2 W1"), IOStandard("LVCMOS33")),
+    ),
+    ("spiflash", 0,
+        Subsignal("cs_n", Pins("R2"), IOStandard("LVCMOS33")),
+        #Subsignal("clk",  Pins("U3"), IOStandard("LVCMOS33")), # Note: CLK is bound using USRMCLK block
+        Subsignal("miso", Pins("V2"), IOStandard("LVCMOS33")),
+        Subsignal("mosi", Pins("W2"), IOStandard("LVCMOS33")),
+        Subsignal("wp",   Pins("Y2"), IOStandard("LVCMOS33")),
+        Subsignal("hold", Pins("W1"), IOStandard("LVCMOS33")),
+    ),
+
+    ("sdcard", 0,
+        Subsignal("clk",  Pins("E11")),
+        Subsignal("cmd",  Pins("D15"), Misc("PULLMODE=UP")),
+        Subsignal("data", Pins("D13 E13 E15 E14"), Misc("PULLMODE=UP")),
+        Subsignal("cd",   Pins("D14"), Misc("PULLMODE=UP")),
+        IOStandard("LVCMOS33"), Misc("SLEW=FAST")
+    ),
+
+    ("spisdcard", 0,
+        Subsignal("clk",  Pins("E11")),
+        Subsignal("mosi", Pins("D15"), Misc("PULLMODE=UP")),
+        Subsignal("cs_n", Pins("E14"), Misc("PULLMODE=UP")),
+        Subsignal("miso", Pins("D13"), Misc("PULLMODE=UP")),
+        Misc("SLEW=FAST"),
+        IOStandard("LVCMOS33"),
+    ),
+
+    ("i2c", 0,
+        Subsignal("sda", Pins("V1")),
+        Subsignal("scl", Pins("U1")),
+        IOStandard("LVCMOS33")
+    ),
+
+    ("eth_clocks", 0,
+        Subsignal("tx", Pins("A15")),
+        Subsignal("rx", Pins("B18")),
+        Subsignal("ref", Pins("A19")),
+        IOStandard("LVCMOS33")
+    ),
+    
+    ("eth", 0,
+        #Subsignal("rst_n",   Pins("U17")), # Stolen for SYS_RESETn on prototypes.
+        Subsignal("int_n",   Pins("B20"), Misc("PULLMODE=UP")), # HACK: Should have a pullup on the board.
+        Subsignal("mdio",    Pins("B19"), Misc("PULLMODE=UP")), # HACK: Should have a pullup on the board.
+        Subsignal("mdc",     Pins("D12")),
+        Subsignal("tx_ctl",  Pins("B15")),
+        Subsignal("tx_data", Pins("A12 A13 C14 A14")),
+        Subsignal("rx_ctl",  Pins("A18")),
+        Subsignal("rx_data", Pins("B17 A17 B16 A16")),
+        IOStandard("LVCMOS33")
+    ),
+]
+
+# Connectors ---------------------------------------------------------------------------------------
+
+_connectors_rev0 = [
+    ("P8",
+        "None",         # No pin 0
+        "None", "None", # GND
+        "C20", "D19",   # P8_LVDS1
+        "D20", "E19",   # P8_LVDS2
+        "E20", "F19",   # P8_LVDS3
+        "F20", "G20",   # P8_LVDS4
+        "None", "None",
+        "None", "None",
+        "None", "None",
+        "None", "None",
+        "None", "None",
+        "None", "None",
+        "G19", "H20",   # P8_LVDS5
+        "J20", "K20",   # P8_LVDS6
+        "C18", "D17",   # P8_LVDS7
+        "D18", "E17",   # P8_LVDS8
+        "E18", "F18",   # P8_LVDS9
+        "F17", "G18",   # P8_LVDS10
+        "E16", "F16",   # P8_LVDS11
+        "G16", "H16",   # P8_LVDS12
+        "J17", "J16",   # P8_LVDS13
+        "H18", "H17",   # P8_LVDS14
+        "J19", "K19",   # P8_LVDS15
+        "J18", "K18"),  # P8_LVDS16
+    ("P9", 
+        "None",         # No pin 0
+        "None", "None", # GND
+        "None", "None", # VCC3V3
+        "None", "None", # CAPE_5V
+        "None", "None", # VBUS
+        "None", "None", # PWR_BUTTON, SYS_RESETn
+        "A11", "B11",   # GPIO11, GPIO12
+        "A10", "C10",   # GPIO13, GPIO14
+        "A9",  "B9",    # GPIO15, GPIO16
+        "C11", "A8",    # GPIO17, GPIO18
+        "None", "None", # I2C Bus
+        "D9",  "C8",    # GPIO21, GPIO22
+        "B8",  "A7",    # GPIO23, GPIO24
+        "A6",  "B6",    # GPIO25, GPIO26
+        "D8",  "C7",    # GPIO27, P9_SPI_CSEL
+        "D7",  "C6",    # P9_SPI_D0, P9_SPI_D1
+        "D6",  "None",  # P9_SPI_SCLK, VADC
+        "None", "None", # AIN4, GNDA
+        "None", "None", # AIN6, AIN5
+        "None", "None", # AIN2, AIN3
+        "None", "None", # AIN0, AIN1
+        "B10", "E10",   # CLKOUT, GPIO42
+        "None", "None", # GND
+        "None", "None") # GND
+]
+
+# Platform -----------------------------------------------------------------------------------------
+
+class Platform(LatticePlatform):
+    default_clk_name   = "refclk"
+    default_clk_period = 1e9/25e6
+
+    def __init__(self, revision="rev0", device="45F", **kwargs):
+        assert revision in ["rev0"]
+        self.revision = revision
+        io         = {"rev0": _io_rev0          }[revision]
+        connectors = {"rev0": _connectors_rev0  }[revision]
+        LatticePlatform.__init__(self, f"LFE5UM5G-{device}-8BG381C", io, connectors, **kwargs)
+
+    def create_programmer(self):
+        return DFUProg(vid="1d50", pid="6130")
+
+    def do_finalize(self, fragment):
+        LatticePlatform.do_finalize(self, fragment)
+        self.add_period_constraint(self.lookup_request("refclk", loose=True), 1e9/25e6)
+        self.add_period_constraint(self.lookup_request("eth_clocks:rx", loose=True), 1e9/125e6)
diff --git a/litex_boards/targets/logicbone.py b/litex_boards/targets/logicbone.py
new file mode 100644
index 0000000000000000000000000000000000000000..46289ff3212fa109b5abb923571bf1c21c2f0e65
--- /dev/null
+++ b/litex_boards/targets/logicbone.py
@@ -0,0 +1,186 @@
+#!/usr/bin/env python3
+
+# This file is Copyright (c) 2020 Owen Kirby <oskirby@gmail.com>
+# License: BSD
+
+import os
+import sys
+import argparse
+
+from migen import *
+from migen.genlib.resetsync import AsyncResetSynchronizer
+
+from litex_boards.platforms import logicbone
+
+from litex.build.lattice.trellis import trellis_args, trellis_argdict
+
+from litex.soc.cores.clock import *
+from litex.soc.integration.soc_core import *
+from litex.soc.integration.soc_sdram import *
+from litex.soc.integration.builder import *
+from litex.soc.cores.led import LedChaser
+
+from litedram.modules import MT41K512M16
+from litedram.phy import ECP5DDRPHY
+from liteeth.phy.ecp5rgmii import LiteEthPHYRGMII
+
+# _CRG ---------------------------------------------------------------------------------------------
+
+class _CRG(Module):
+    def __init__(self, platform, sys_clk_freq, with_usb_pll=False):
+        self.clock_domains.cd_init     = ClockDomain()
+        self.clock_domains.cd_por      = ClockDomain(reset_less=True)
+        self.clock_domains.cd_sys      = ClockDomain()
+        self.clock_domains.cd_sys2x    = ClockDomain()
+        self.clock_domains.cd_sys2x_i  = ClockDomain(reset_less=True)
+        self.clock_domains.cd_sys2x_eb = ClockDomain(reset_less=True)
+        self.clock_domains.cd_clk10    = ClockDomain()
+
+
+        # # #
+
+        self.stop = Signal()
+
+        # Clk / Rst
+        clk25 = platform.request("refclk")
+
+        # Power on reset
+        por_count = Signal(16, reset=2**16-1)
+        por_done  = Signal()
+        self.comb += self.cd_por.clk.eq(ClockSignal())
+        self.comb += por_done.eq(por_count == 0)
+        self.sync.por += If(~por_done, por_count.eq(por_count - 1))
+
+        # PLL
+        sys2x_clk_ecsout = Signal()
+        self.submodules.pll = pll = ECP5PLL()
+        pll.register_clkin(clk25, 25e6)
+        pll.create_clkout(self.cd_sys2x_i, 2*sys_clk_freq)
+        pll.create_clkout(self.cd_init, 24e6)
+        pll.create_clkout(self.cd_clk10, 10e6)
+        self.specials += [
+            Instance("ECLKBRIDGECS",
+                i_CLK0   = self.cd_sys2x_i.clk,
+                i_SEL    = 0,
+                o_ECSOUT = sys2x_clk_ecsout),
+            Instance("ECLKSYNCB",
+                i_ECLKI = sys2x_clk_ecsout,
+                i_STOP  = self.stop,
+                o_ECLKO = self.cd_sys2x.clk),
+            Instance("CLKDIVF",
+                p_DIV     = "2.0",
+                i_ALIGNWD = 0,
+                i_CLKI    = self.cd_sys2x.clk,
+                i_RST     = self.cd_sys2x.rst,
+                o_CDIVX   = self.cd_sys.clk),
+            AsyncResetSynchronizer(self.cd_init, ~por_done | ~pll.locked),
+            AsyncResetSynchronizer(self.cd_sys,  ~por_done | ~pll.locked),
+            AsyncResetSynchronizer(self.cd_clk10, ~por_done | ~pll.locked)
+        ]
+
+        # USB PLL
+        if with_usb_pll:
+            self.clock_domains.cd_usb_12 = ClockDomain()
+            self.clock_domains.cd_usb_48 = ClockDomain()
+            usb_pll = ECP5PLL()
+            self.submodules += usb_pll
+            usb_pll.register_clkin(clk25, 25e6)
+            usb_pll.create_clkout(self.cd_usb_48, 48e6)
+            usb_pll.create_clkout(self.cd_usb_12, 12e6)
+
+# BaseSoC ------------------------------------------------------------------------------------------
+
+class BaseSoC(SoCCore):
+    def __init__(self, revision="rev0", device="45F", sdram_device="MT41K512M16",
+                 with_ethernet=False,
+                 sys_clk_freq=int(75e6), toolchain="trellis", **kwargs):
+        platform = logicbone.Platform(revision=revision, device=device ,toolchain=toolchain)
+
+        # Serial -----------------------------------------------------------------------------------
+        if kwargs["uart_name"] == "usb_acm":
+            # FIXME: do proper install of ValentyUSB.
+            os.system("git clone https://github.com/gregdavill/valentyusb -b hw_cdc_eptri")
+            sys.path.append("valentyusb")
+
+        # SoCCore ----------------------------------------------------------------------------------
+        SoCCore.__init__(self, platform, clk_freq=sys_clk_freq, **kwargs)
+
+        # CRG --------------------------------------------------------------------------------------
+        with_usb_pll = kwargs.get("uart_name", None) == "usb_acm"
+        self.submodules.crg = _CRG(platform, sys_clk_freq, with_usb_pll)
+
+        # DDR3 SDRAM -------------------------------------------------------------------------------
+        if not self.integrated_main_ram_size:
+            available_sdram_modules = {
+                "MT41K512M16":  MT41K512M16,
+                #"AS4C1GM8":    AS4C1GM8, ## Too many rows, seems to break things.
+            }
+            sdram_module = available_sdram_modules.get(sdram_device)
+
+            self.submodules.ddrphy = ECP5DDRPHY(
+                platform.request("ddram"),
+                sys_clk_freq=sys_clk_freq)
+            self.add_csr("ddrphy")
+            self.comb += self.crg.stop.eq(self.ddrphy.init.stop)
+            self.add_sdram("sdram",
+                phy                     = self.ddrphy,
+                module                  = sdram_module(sys_clk_freq, "1:2"),
+                origin                  = self.mem_map["main_ram"],
+                size                    = kwargs.get("max_sdram_size", 0x40000000),
+                l2_cache_size           = kwargs.get("l2_size", 8192),
+                l2_cache_min_data_width = kwargs.get("min_l2_data_width", 128),
+                l2_cache_reverse        = True
+            )
+
+        # Ethernet ---------------------------------------------------------------------------------
+        if with_ethernet:
+            self.submodules.ethphy = LiteEthPHYRGMII(
+                clock_pads = self.platform.request("eth_clocks"),
+                pads       = self.platform.request("eth"))
+            self.add_csr("ethphy")
+            self.add_ethernet(phy=self.ethphy)
+
+
+        # Leds -------------------------------------------------------------------------------------
+        self.submodules.leds = LedChaser(
+            pads         = Cat(*[platform.request("user_led", i) for i in range(4)]),
+            sys_clk_freq = sys_clk_freq)
+        self.add_csr("leds")
+
+# Build --------------------------------------------------------------------------------------------
+
+def main():
+    parser = argparse.ArgumentParser(description="LiteX SoC on Logicbone")
+    parser.add_argument("--build", action="store_true", help="Build bitstream")
+    parser.add_argument("--load",  action="store_true", help="Load bitstream")
+    parser.add_argument("--toolchain", default="trellis", help="Gateware toolchain to use, trellis (default) or diamond")
+    builder_args(parser)
+    soc_sdram_args(parser)
+    trellis_args(parser)
+    parser.add_argument("--sys-clk-freq",   default=75e6,           help="System clock frequency (default=75MHz)")
+    parser.add_argument("--device",         default="45F",          help="ECP5 device (default=45F)")
+    parser.add_argument("--sdram-device",   default="MT41K512M16",  help="ECP5 device (default=MT41K512M16)")
+    parser.add_argument("--with-ethernet",  action="store_true",    help="enable Ethernet support")
+    parser.add_argument("--with-sdcard",    action="store_true",    help="enable SDCard support")
+    args = parser.parse_args()
+    
+    soc = BaseSoC(
+        toolchain    = args.toolchain,
+        revision     = args.revision,
+        device       = args.device,
+        sdram_device = args.sdram_device,
+        with_ethernet=args.with_ethernet,
+        sys_clk_freq = int(float(args.sys_clk_freq)),
+        **soc_sdram_argdict(args))
+    if args.with_sdcard:
+        soc.add_sdcard()
+    builder = Builder(soc, **builder_argdict(args))
+    builder_kargs = trellis_argdict(args) if args.toolchain == "trellis" else {}
+    builder.build(**builder_kargs, run=args.build)
+
+    if args.load:
+        prog = soc.platform.create_programmer()
+        prog.load_bitstream(os.path.join(builder.gateware_dir, soc.build_name + ".bit"))
+
+if __name__ == "__main__":
+    main()