From 88eeafae12b78798f6b886b2d4193b5fa64bac4c Mon Sep 17 00:00:00 2001 From: Simon Schubert <2@0x2c.org> Date: Mon, 10 Jun 2019 11:30:01 +0200 Subject: ice40: add RGB_DRV/LED_DRV_CUR support for u4k --- ice40/arch.cc | 8 ++++++++ ice40/archdefs.h | 4 ++++ ice40/bitstream.cc | 7 +++++++ ice40/cells.cc | 16 ++++++++++++++++ ice40/cells.h | 4 ++++ ice40/chipdb.py | 2 ++ ice40/constids.inc | 5 +++++ ice40/pack.cc | 35 +++++++++++++++++++++++++++++++---- 8 files changed, 77 insertions(+), 4 deletions(-) (limited to 'ice40') diff --git a/ice40/arch.cc b/ice40/arch.cc index d536ad35..80e1fb4c 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -1045,6 +1045,14 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in return TMG_COMB_INPUT; } else if (cell->type == id_SB_WARMBOOT) { return TMG_ENDPOINT; + } else if (cell->type == id_SB_LED_DRV_CUR) { + if (port == id_LEDPU) + return TMG_IGNORE; + return TMG_ENDPOINT; + } else if (cell->type == id_SB_RGB_DRV) { + if (port == id_RGB0 || port == id_RGB1 || port == id_RGB2 || port == id_RGBPU) + return TMG_IGNORE; + return TMG_ENDPOINT; } else if (cell->type == id_SB_RGBA_DRV) { if (port == id_RGB0 || port == id_RGB1 || port == id_RGB2) return TMG_IGNORE; diff --git a/ice40/archdefs.h b/ice40/archdefs.h index 956fcb4c..89591af5 100644 --- a/ice40/archdefs.h +++ b/ice40/archdefs.h @@ -159,6 +159,10 @@ struct ArchCellInfo { bool forPadIn; } gbInfo; + struct + { + bool ledCurConnected; + } ledInfo; }; }; diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 9b85dff5..d35c43aa 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -610,6 +610,13 @@ void write_asc(const Context *ctx, std::ostream &out) set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_1", write_mode & 0x2); set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_2", read_mode & 0x1); set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_3", read_mode & 0x2); + } else if (cell.second->type == ctx->id("SB_LED_DRV_CUR")) { + set_ec_cbit(config, ctx, get_ec_config(ctx->chip_info, cell.second->bel), "LED_DRV_CUR_EN", true, "IpConfig."); + } else if (cell.second->type == ctx->id("SB_RGB_DRV")) { + const std::vector> rgb_params = { + {"RGB0_CURRENT", 6}, {"RGB1_CURRENT", 6}, {"RGB2_CURRENT", 6}}; + configure_extra_cell(config, ctx, cell.second.get(), rgb_params, true, std::string("IpConfig.")); + set_ec_cbit(config, ctx, get_ec_config(ctx->chip_info, cell.second->bel), "RGB_DRV_EN", true, "IpConfig."); } else if (cell.second->type == ctx->id("SB_RGBA_DRV")) { const std::vector> rgba_params = { {"CURRENT_MODE", 1}, {"RGB0_CURRENT", 6}, {"RGB1_CURRENT", 6}, {"RGB2_CURRENT", 6}}; diff --git a/ice40/cells.cc b/ice40/cells.cc index 5744fe50..a2abcea4 100644 --- a/ice40/cells.cc +++ b/ice40/cells.cc @@ -260,6 +260,22 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri add_port(ctx, new_cell.get(), "RGB0", PORT_OUT); add_port(ctx, new_cell.get(), "RGB1", PORT_OUT); add_port(ctx, new_cell.get(), "RGB2", PORT_OUT); + } else if (type == ctx->id("SB_LED_DRV_CUR")) { + add_port(ctx, new_cell.get(), "EN", PORT_IN); + add_port(ctx, new_cell.get(), "LEDPU", PORT_OUT); + } else if (type == ctx->id("SB_RGB_DRV")) { + new_cell->params[ctx->id("RGB0_CURRENT")] = "0b000000"; + new_cell->params[ctx->id("RGB1_CURRENT")] = "0b000000"; + new_cell->params[ctx->id("RGB2_CURRENT")] = "0b000000"; + + add_port(ctx, new_cell.get(), "RGBPU", PORT_IN); + add_port(ctx, new_cell.get(), "RGBLEDEN", PORT_IN); + add_port(ctx, new_cell.get(), "RGB0PWM", PORT_IN); + add_port(ctx, new_cell.get(), "RGB1PWM", PORT_IN); + add_port(ctx, new_cell.get(), "RGB2PWM", PORT_IN); + add_port(ctx, new_cell.get(), "RGB0", PORT_OUT); + add_port(ctx, new_cell.get(), "RGB1", PORT_OUT); + add_port(ctx, new_cell.get(), "RGB2", PORT_OUT); } else if (type == ctx->id("SB_LEDDA_IP")) { add_port(ctx, new_cell.get(), "LEDDCS", PORT_IN); add_port(ctx, new_cell.get(), "LEDDCLK", PORT_IN); diff --git a/ice40/cells.h b/ice40/cells.h index ec4d560d..25a98573 100644 --- a/ice40/cells.h +++ b/ice40/cells.h @@ -76,6 +76,10 @@ inline bool is_sb_mac16(const BaseCtx *ctx, const CellInfo *cell) { return cell- inline bool is_sb_rgba_drv(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_RGBA_DRV"); } +inline bool is_sb_rgb_drv(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_RGB_DRV"); } + +inline bool is_sb_led_drv_cur(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_LED_DRV_CUR"); } + inline bool is_sb_ledda_ip(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_LEDDA_IP"); } inline bool is_sb_i2c(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_I2C"); } diff --git a/ice40/chipdb.py b/ice40/chipdb.py index 42ca6ac1..cc7be01f 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -81,6 +81,8 @@ constids["SPI"] = constids["SB_SPI"] constids["LEDDA_IP"] = constids["SB_LEDDA_IP"] constids["RGBA_DRV"] = constids["SB_RGBA_DRV"] constids["SPRAM"] = constids["ICESTORM_SPRAM"] +constids["LED_DRV_CUR"] = constids["SB_LED_DRV_CUR"] +constids["RGB_DRV"] = constids["SB_RGB_DRV"] with open(args.gfxh) as f: state = 0 diff --git a/ice40/constids.inc b/ice40/constids.inc index 366a3a9d..6aa5c4c0 100644 --- a/ice40/constids.inc +++ b/ice40/constids.inc @@ -355,6 +355,9 @@ X(PWMOUT0) X(PWMOUT1) X(PWMOUT2) +X(LEDPU) +X(EN) +X(RGBPU) X(CURREN) X(RGB0PWM) X(RGB1PWM) @@ -438,6 +441,8 @@ X(IO_I3C) X(SB_LEDDA_IP) X(SB_RGBA_DRV) X(ICESTORM_SPRAM) +X(SB_LED_DRV_CUR) +X(SB_RGB_DRV) // cell parameters X(DFF_ENABLE) diff --git a/ice40/pack.cc b/ice40/pack.cc index 390cbf57..9a77048b 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -450,7 +450,7 @@ static void pack_io(Context *ctx) } else if (ci->type == ctx->id("$nextpnr_obuf")) { NetInfo *net = ci->ports.at(ctx->id("I")).net; sb = net_only_drives(ctx, net, is_ice_iob, ctx->id("PACKAGE_PIN"), true, ci); - if (net && net->driver.cell && is_sb_rgba_drv(ctx, net->driver.cell)) + if (net && net->driver.cell && (is_sb_rgba_drv(ctx, net->driver.cell) || is_sb_rgb_drv(ctx, net->driver.cell))) rgb = net->driver.cell; } if (sb != nullptr) { @@ -476,7 +476,7 @@ static void pack_io(Context *ctx) } } } else if (rgb != nullptr) { - log_info("%s use by SB_RGBA_DRV %s, not creating SB_IO\n", ci->name.c_str(ctx), rgb->name.c_str(ctx)); + log_info("%s use by SB_RGBA_DRV/SB_RGB_DRV %s, not creating SB_IO\n", ci->name.c_str(ctx), rgb->name.c_str(ctx)); disconnect_port(ctx, ci, ctx->id("I")); packed_cells.insert(ci->name); continue; @@ -1038,6 +1038,27 @@ static void pack_special(Context *ctx) std::unordered_set packed_cells; std::vector> new_cells; + // Handle LED_DRV_CUR first to set the ledCurConnected flag before RGB_DRV is handled below. + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (is_sb_led_drv_cur(ctx, ci)) { + /* Force placement (no choices anyway) */ + cell_place_unique(ctx, ci); + + NetInfo *ledpu_net = ci->ports.at(ctx->id("LEDPU")).net; + for (auto &user : ledpu_net->users) { + if (!is_sb_rgb_drv(ctx, user.cell)) { + log_error("SB_LED_DRV_CUR LEDPU port can only be connected to SB_RGB_DRV!\n"); + } else { + user.cell->ledInfo.ledCurConnected = true; + user.cell->ports.at(user.port).net = nullptr; + } + } + ci->ports.erase(ctx->id("LEDPU")); + ctx->nets.erase(ledpu_net->name); + } + } + for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (is_sb_lfosc(ctx, ci)) { @@ -1113,7 +1134,7 @@ static void pack_special(Context *ctx) replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); } new_cells.push_back(std::move(packed)); - } else if (is_sb_rgba_drv(ctx, ci)) { + } else if (is_sb_rgba_drv(ctx, ci) || is_sb_rgb_drv(ctx, ci)) { /* Force placement (no choices anyway) */ cell_place_unique(ctx, ci); @@ -1125,14 +1146,20 @@ static void pack_special(Context *ctx) if (net == nullptr) continue; + if ((pi.name != ctx->id("RGB0")) && (pi.name != ctx->id("RGB1")) && (pi.name != ctx->id("RGB2"))) continue; if (net->users.size() > 0) - log_error("SB_RGBA_DRV port connected to more than just package pin !\n"); + log_error("SB_RGB_DRV/SB_RGBA_DRV port connected to more than just package pin !\n"); ctx->nets.erase(net->name); } + + if (is_sb_rgb_drv(ctx, ci) && !ci->ledInfo.ledCurConnected) + log_error("Port RGBPU of SB_RGB_DRV should be driven by port LEDPU of SB_LED_DRV_CUR!\n"); + + ci->ports.erase(ctx->id("RGBPU")); ci->ports.erase(ctx->id("RGB0")); ci->ports.erase(ctx->id("RGB1")); ci->ports.erase(ctx->id("RGB2")); -- cgit v1.2.3