/* Abort if we are using an untested phy. */ if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 &&
BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 &&
BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M &&
BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54210E &&
BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54810 &&
BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811) return;
val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3); if (val < 0) return;
orig = val;
if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
BRCM_PHY_REV(phydev) >= 0x3) { /* * Here, bit 0 _disables_ CLK125 when set. * This bit is set by default.
*/
clk125en = false;
} else { if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) { if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811) { /* Here, bit 0 _enables_ CLK125 when set */
val &= ~BCM54XX_SHD_SCR3_DEF_CLK125;
}
clk125en = false;
}
}
if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS; else
val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) { if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E ||
BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810 ||
BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54811)
val |= BCM54XX_SHD_SCR3_RXCTXC_DIS; else
val |= BCM54XX_SHD_SCR3_TRDDAPD;
}
if (orig != val)
bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD); if (val < 0) return;
orig = val;
if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
val |= BCM54XX_SHD_APD_EN; else
val &= ~BCM54XX_SHD_APD_EN;
if (orig != val)
bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
}
if (on)
reg |= BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN; else
reg &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
err = bcm_phy_write_exp(phydev,
BCM54810_EXP_BROADREACH_LRE_MISC_CTL, reg); if (err) return err;
/* Ensure LRE or IEEE register set is accessed according to the brr * on/off, thus set the override
*/
val = BCM54811_EXP_BROADREACH_LRE_OVERLAY_CTL_EN; if (!on)
val |= BCM54811_EXP_BROADREACH_LRE_OVERLAY_CTL_OVERRIDE_VAL;
/* Enable CLK125 MUX on LED4 if ref clock is enabled. */ if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) {
reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0); if (reg < 0) return reg;
err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0,
BCM54612E_LED4_CLK125OUT_EN | reg); if (err < 0) return err;
}
/* With BCM54811, BroadR-Reach implies no autoneg */ if (priv->brr_mode)
phydev->autoneg = 0;
/* Enable MII Lite (No TXER, RXER, CRS, COL) if configured */ if (phydev->interface == PHY_INTERFACE_MODE_MIILITE)
exp_sync_ethernet = BCM_EXP_SYNC_ETHERNET_MII_LITE; else
exp_sync_ethernet = 0;
/* Enable RGMII if configured */ if (phy_interface_is_rgmii(phydev))
aux_rgmii_en = MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_EN |
MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; else
aux_rgmii_en = 0;
/* Also writing Reserved bits 6:5 because the documentation requires * them to be written to 0b11
*/
err = bcm54xx_auxctl_write(phydev,
MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
MII_BCM54XX_AUXCTL_MISC_WREN |
aux_rgmii_en |
MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RSVD); if (err < 0) return err;
switch (BRCM_PHY_MODEL(phydev)) { case PHY_ID_BCM50610: case PHY_ID_BCM50610M:
err = bcm54xx_config_clock_delay(phydev); break; case PHY_ID_BCM54210E:
err = bcm54210e_config_init(phydev); break; case PHY_ID_BCM54612E:
err = bcm54612e_config_init(phydev); break; case PHY_ID_BCM54616S:
err = bcm54616s_config_init(phydev); break; case PHY_ID_BCM54810: /* For BCM54810, we need to disable BroadR-Reach function */
val = bcm_phy_read_exp(phydev,
BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
err = bcm_phy_write_exp(phydev,
BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
val); break; case PHY_ID_BCM54811:
err = bcm54811_config_init(phydev); break;
} if (err) return err;
bcm54xx_phydsp_config(phydev);
/* For non-SFP setups, encode link speed into LED1 and LED3 pair * (green/amber). * Also flash these two LEDs on activity. This means configuring * them for MULTICOLOR and encoding link/activity into them. * Don't do this for devices on an SFP module, since some of these * use the LED outputs to control the SFP LOS signal, and changing * these settings will cause LOS to malfunction.
*/ if (!phy_on_sfp(phydev)) {
val = BCM54XX_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) |
BCM54XX_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1);
bcm_phy_write_shadow(phydev, BCM54XX_SHD_LEDS1, val);
/* Acknowledge any left over interrupt and charge the device for * wake-up.
*/
err = bcm_phy_read_exp(phydev, BCM54XX_WOL_INT_STATUS); if (err < 0) return err;
if (err)
pm_wakeup_event(&phydev->mdio.dev, 0);
return 0;
}
staticint bcm54xx_iddq_set(struct phy_device *phydev, bool enable)
{ int ret = 0;
if (!(phydev->dev_flags & PHY_BRCM_IDDQ_SUSPEND)) return ret;
ret = bcm_phy_read_exp(phydev, BCM54XX_TOP_MISC_IDDQ_CTRL); if (ret < 0) goto out;
if (enable)
ret |= BCM54XX_TOP_MISC_IDDQ_SR | BCM54XX_TOP_MISC_IDDQ_LP; else
ret &= ~(BCM54XX_TOP_MISC_IDDQ_SR | BCM54XX_TOP_MISC_IDDQ_LP);
ret = bcm_phy_write_exp(phydev, BCM54XX_TOP_MISC_IDDQ_CTRL, ret);
out: return ret;
}
staticint bcm54xx_set_wakeup_irq(struct phy_device *phydev, bool state)
{ struct bcm54xx_phy_priv *priv = phydev->priv; int ret = 0;
if (!bcm54xx_phy_can_wakeup(phydev)) return ret;
if (priv->wake_irq_enabled != state) { if (state)
ret = enable_irq_wake(priv->wake_irq); else
ret = disable_irq_wake(priv->wake_irq);
priv->wake_irq_enabled = state;
}
return ret;
}
staticint bcm54xx_suspend(struct phy_device *phydev)
{ int ret = 0;
bcm54xx_ptp_stop(phydev);
/* Acknowledge any Wake-on-LAN interrupt prior to suspend */
ret = bcm_phy_read_exp(phydev, BCM54XX_WOL_INT_STATUS); if (ret < 0) return ret;
if (phydev->wol_enabled) return bcm54xx_set_wakeup_irq(phydev, true);
/* We cannot use a read/modify/write here otherwise the PHY gets into * a bad state where its LEDs keep flashing, thus defeating the purpose * of low power mode.
*/
ret = phy_write(phydev, MII_BMCR, BMCR_PDOWN); if (ret < 0) return ret;
return bcm54xx_iddq_set(phydev, true);
}
staticint bcm54xx_resume(struct phy_device *phydev)
{ int ret = 0;
if (phydev->wol_enabled) {
ret = bcm54xx_set_wakeup_irq(phydev, false); if (ret) return ret;
}
ret = bcm54xx_iddq_set(phydev, false); if (ret < 0) return ret;
/* Writes to register other than BMCR would be ignored * unless we clear the PDOWN bit first
*/
ret = genphy_resume(phydev); if (ret < 0) return ret;
/* Upon exiting power down, the PHY remains in an internal reset state * for 40us
*/
fsleep(40);
/* Issue a soft reset after clearing the power down bit * and before doing any other configuration.
*/ if (phydev->dev_flags & PHY_BRCM_IDDQ_SUSPEND) {
ret = genphy_soft_reset(phydev); if (ret < 0) return ret;
}
/** * bcm5481x_read_abilities - read PHY abilities from LRESR or Clause 22 * (BMSR) registers, based on whether the PHY is in BroadR-Reach or IEEE mode * @phydev: target phy_device struct * * Description: Reads the PHY's abilities and populates phydev->supported * accordingly. The register to read the abilities from is determined by * the brr mode setting of the PHY as read from the device tree. * Note that the LRE and IEEE sets of abilities are disjunct, in other words, * not only the link modes differ, but also the auto-negotiation and * master-slave setup is controlled differently. * * Returns: 0 on success, < 0 on failure
*/ staticint bcm5481x_read_abilities(struct phy_device *phydev)
{ struct device_node *np = phydev->mdio.dev.of_node; struct bcm54xx_phy_priv *priv = phydev->priv; int i, val, err, aneg;
for (i = 0; i < ARRAY_SIZE(bcm54811_linkmodes); i++)
linkmode_clear_bit(bcm54811_linkmodes[i], phydev->supported);
/* Set BroadR-Reach mode as configured in the DT. */
err = bcm5481x_set_brrmode(phydev, priv->brr_mode); if (err) return err;
if (priv->brr_mode) {
linkmode_set_bit_array(phy_basic_ports_array,
ARRAY_SIZE(phy_basic_ports_array),
phydev->supported);
val = phy_read(phydev, MII_BCM54XX_LRESR); if (val < 0) return val;
/* BCM54811 is not capable of LDS but the corresponding bit * in LRESR is set to 1 and marked "Ignore" in the datasheet. * So we must read the bcm54811 as unable to auto-negotiate * in BroadR-Reach mode.
*/ if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54811)
aneg = 0; else
aneg = val & LRESR_LDSABILITY;
linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
phydev->supported,
aneg);
linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
phydev->supported,
val & LRESR_100_1PAIR);
linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT1BRR_Full_BIT,
phydev->supported,
val & LRESR_10_1PAIR); return 0;
}
/* Aneg firstly. */ if (priv->brr_mode) { /* BCM54811 is only capable of autonegotiation in IEEE mode. * In BroadR-Reach mode, disable the Long Distance Signaling, * the BRR mode autoneg as supported in other Broadcom PHYs. * This bit is marked as "Reserved" and "Default 1, must be * written to 0 after every device reset" in the datasheet.
*/
ret = phy_modify(phydev, MII_BCM54XX_LRECR, LRECR_LDSEN, 0); if (ret < 0) return ret;
ret = bcm_config_lre_aneg(phydev, false);
} else {
ret = genphy_config_aneg(phydev);
}
if (ret) return ret;
/* Then we can set up the delay and swap. */ return bcm5481x_config_delay_swap(phydev);
}
staticint bcm54616s_probe(struct phy_device *phydev)
{ struct bcm54616s_phy_priv *priv; int val;
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM;
phydev->priv = priv;
val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE); if (val < 0) return val;
/* The PHY is strapped in RGMII-fiber mode when INTERF_SEL[1:0] * is 01b, and the link between PHY and its link partner can be * either 1000Base-X or 100Base-FX. * RGMII-1000Base-X is properly supported, but RGMII-100Base-FX * support is still missing as of now.
*/ if ((val & BCM54XX_SHD_INTF_SEL_MASK) == BCM54XX_SHD_INTF_SEL_RGMII) {
val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL); if (val < 0) return val;
/* Bit 0 of the SerDes 100-FX Control register, when set * to 1, sets the MII/RGMII -> 100BASE-FX configuration. * When this bit is set to 0, it sets the GMII/RGMII -> * 1000BASE-X configuration.
*/ if (!(val & BCM54616S_100FX_MODE))
priv->mode_1000bx_en = true;
if (priv->mode_1000bx_en)
err = genphy_c37_read_status(phydev, &changed); else
err = genphy_read_status(phydev);
return err;
}
staticint brcm_fet_config_init(struct phy_device *phydev)
{ int reg, err, err2, brcmtest;
/* Reset the PHY to bring it to a known state. */
err = phy_write(phydev, MII_BMCR, BMCR_RESET); if (err < 0) return err;
/* The datasheet indicates the PHY needs up to 1us to complete a reset, * build some slack here.
*/
usleep_range(1000, 2000);
/* The PHY requires 65 MDC clock cycles to complete a write operation * and turnaround the line properly. * * We ignore -EIO here as the MDIO controller (e.g.: mdio-bcm-unimac) * may flag the lack of turn-around as a read failure. This is * particularly true with this combination since the MDIO controller * only used 64 MDC cycles. This is not a critical failure in this * specific case and it has no functional impact otherwise, so we let * that one go through. If there is a genuine bus error, the next read * of MII_BRCM_FET_INTREG will error out.
*/
err = phy_read(phydev, MII_BMCR); if (err < 0 && err != -EIO) return err;
/* Read to clear status bits */
reg = phy_read(phydev, MII_BRCM_FET_INTREG); if (reg < 0) return reg;
/* Unmask events we are interested in and mask interrupts globally. */ if (phydev->drv->phy_id == PHY_ID_BCM5221)
reg = MII_BRCM_FET_IR_ENABLE |
MII_BRCM_FET_IR_MASK; else
reg = MII_BRCM_FET_IR_DUPLEX_EN |
MII_BRCM_FET_IR_SPEED_EN |
MII_BRCM_FET_IR_LINK_EN |
MII_BRCM_FET_IR_ENABLE |
MII_BRCM_FET_IR_MASK;
/* Enable auto MDIX */
err = __phy_set_bits(phydev, MII_BRCM_FET_SHDW_MISCCTRL,
MII_BRCM_FET_SHDW_MC_FAME); if (err < 0) goto done;
}
if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) { /* Enable auto power down */
err = __phy_set_bits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
MII_BRCM_FET_SHDW_AS2_APDE);
}
staticint brcm_fet_suspend(struct phy_device *phydev)
{ int reg, err, err2, brcmtest;
/* We cannot use a read/modify/write here otherwise the PHY continues * to drive LEDs which defeats the purpose of low power mode.
*/
err = phy_write(phydev, MII_BMCR, BMCR_PDOWN); if (err < 0) return err;
staticint bcm5221_config_aneg(struct phy_device *phydev)
{ int ret, val;
ret = genphy_config_aneg(phydev); if (ret) return ret;
switch (phydev->mdix_ctrl) { case ETH_TP_MDI:
val = BCM5221_AEGSR_MDIX_DIS; break; case ETH_TP_MDI_X:
val = BCM5221_AEGSR_MDIX_DIS | BCM5221_AEGSR_MDIX_MAN_SWAP; break; case ETH_TP_MDI_AUTO:
val = 0; break; default: return 0;
}
staticvoid bcm54xx_phy_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
{ /* We cannot wake-up if we do not have a dedicated PHY interrupt line * or an out of band GPIO descriptor for wake-up. Zeroing * wol->supported allows the caller (MAC driver) to play through and * offer its own Wake-on-LAN scheme if available.
*/ if (!bcm54xx_phy_can_wakeup(phydev)) {
wol->supported = 0; return;
}
bcm_phy_get_wol(phydev, wol);
}
staticint bcm54xx_phy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
{ int ret;
/* We cannot wake-up if we do not have a dedicated PHY interrupt line * or an out of band GPIO descriptor for wake-up. Returning -EOPNOTSUPP * allows the caller (MAC driver) to play through and offer its own * Wake-on-LAN scheme if available.
*/ if (!bcm54xx_phy_can_wakeup(phydev)) return -EOPNOTSUPP;
ret = bcm_phy_set_wol(phydev, wol); if (ret < 0) return ret;
return 0;
}
staticint bcm54xx_phy_probe(struct phy_device *phydev)
{ struct bcm54xx_phy_priv *priv; struct gpio_desc *wakeup_gpio; int ret = 0;
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM;
priv->wake_irq = -ENXIO;
phydev->priv = priv;
priv->stats = devm_kcalloc(&phydev->mdio.dev,
bcm_phy_get_sset_count(phydev), sizeof(u64),
GFP_KERNEL); if (!priv->stats) return -ENOMEM;
priv->ptp = bcm_ptp_probe(phydev); if (IS_ERR(priv->ptp)) return PTR_ERR(priv->ptp);
/* We cannot utilize the _optional variant here since we want to know * whether the GPIO descriptor exists or not to advertise Wake-on-LAN * support or not.
*/
wakeup_gpio = devm_gpiod_get(&phydev->mdio.dev, "wakeup", GPIOD_IN); if (PTR_ERR(wakeup_gpio) == -EPROBE_DEFER) return PTR_ERR(wakeup_gpio);
if (!IS_ERR(wakeup_gpio)) {
priv->wake_irq = gpiod_to_irq(wakeup_gpio);
/* Dummy interrupt handler which is not enabled but is provided * in order for the interrupt descriptor to be fully set-up.
*/
ret = devm_request_irq(&phydev->mdio.dev, priv->wake_irq,
bcm_phy_wol_isr,
IRQF_TRIGGER_LOW | IRQF_NO_AUTOEN,
dev_name(&phydev->mdio.dev), phydev); if (ret) return ret;
}
/* If we do not have a main interrupt or a side-band wake-up interrupt, * then the device cannot be marked as wake-up capable.
*/ if (!bcm54xx_phy_can_wakeup(phydev)) return 0;
/* Don't change the DAC wake settings if auto power down * is not requested.
*/ if (!(phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE)) return;
ret = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP08); if (ret < 0) return;
/* Enable/disable 10BaseT auto and forced early DAC wake depending * on the negotiated speed, those settings should only be done * for 10Mbits/sec.
*/ if (phydev->speed == SPEED_10)
ret |= mask; else
ret &= ~mask;
bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08, ret);
}
staticint lre_read_master_slave(struct phy_device *phydev)
{ int cfg = MASTER_SLAVE_CFG_UNKNOWN, state; int val;
/* In BroadR-Reach mode we are always capable of master-slave * and there is no preferred master or slave configuration
*/
phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN;
phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
val = phy_read(phydev, MII_BCM54XX_LRECR); if (val < 0) return val;
if ((val & LRECR_LDSEN) == 0) { if (val & LRECR_MASTER)
cfg = MASTER_SLAVE_CFG_MASTER_FORCE; else
cfg = MASTER_SLAVE_CFG_SLAVE_FORCE;
}
val = phy_read(phydev, MII_BCM54XX_LRELDSE); if (val < 0) return val;
if (val & LDSE_MASTER)
state = MASTER_SLAVE_STATE_MASTER; else
state = MASTER_SLAVE_STATE_SLAVE;
/* Read LDS Link Partner Ability in BroadR-Reach mode */ staticint lre_read_lpa(struct phy_device *phydev)
{ int i, lrelpa;
if (phydev->autoneg != AUTONEG_ENABLE) { if (!phydev->autoneg_complete) { /* aneg not yet done, reset all relevant bits */ for (i = 0; i < ARRAY_SIZE(lds_br_bits); i++)
linkmode_clear_bit(lds_br_bits[i],
phydev->lp_advertising);
return 0;
}
/* Long-Distance Signaling Link Partner Ability */
lrelpa = phy_read(phydev, MII_BCM54XX_LRELPA); if (lrelpa < 0) return lrelpa;
/** * lre_update_link - update link status in @phydev * @phydev: target phy_device struct * Return: 0 on success, < 0 on error * * Description: Update the value in phydev->link to reflect the * current link value. In order to do this, we need to read * the status register twice, keeping the second value. * This is a genphy_update_link modified to work on LRE registers * of BroadR-Reach PHY
*/ staticint lre_update_link(struct phy_device *phydev)
{ int status = 0, lrecr;
lrecr = phy_read(phydev, MII_BCM54XX_LRECR); if (lrecr < 0) return lrecr;
/* Autoneg is being started, therefore disregard BMSR value and * report link as down.
*/ if (lrecr & BMCR_ANRESTART) goto done;
/* The link state is latched low so that momentary link * drops can be detected. Do not double-read the status * in polling mode to detect such short link drops except * the link was already down.
*/ if (!phy_polling_mode(phydev) || !phydev->link) {
status = phy_read(phydev, MII_BCM54XX_LRESR); if (status < 0) return status; elseif (status & LRESR_LSTATUS) goto done;
}
/* Read link and autonegotiation status */
status = phy_read(phydev, MII_BCM54XX_LRESR); if (status < 0) return status;
done:
phydev->link = status & LRESR_LSTATUS ? 1 : 0;
phydev->autoneg_complete = status & LRESR_LDSCOMPLETE ? 1 : 0;
/* Consider the case that autoneg was started and "aneg complete" * bit has been reset, but "link up" bit not yet.
*/ if (phydev->autoneg == AUTONEG_ENABLE && !phydev->autoneg_complete)
phydev->link = 0;
return 0;
}
/* Get the status in BroadRReach mode just like genphy_read_status does * in normal mode
*/ staticint bcm54811_lre_read_status(struct phy_device *phydev)
{ int err, old_link = phydev->link;
/* Update the link, but return if there was an error */
err = lre_update_link(phydev); if (err) return err;
/* why bother the PHY if nothing can have changed */ if (phydev->autoneg ==
AUTONEG_ENABLE && old_link && phydev->link) return 0;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.6Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.