Index: share/man/man9/bhnd.9 =================================================================== --- share/man/man9/bhnd.9 +++ share/man/man9/bhnd.9 @@ -266,9 +266,9 @@ .Fa "device_t dev" "bus_size_t offset" "const void *value" "u_int width" .Fc .Ft int -.Fn bhnd_reset_hw "device_t dev" "uint16_t ioctl" +.Fn bhnd_reset_hw "device_t dev" "uint16_t ioctl" "uint16_t reset_ioctl" .Ft int -.Fn bhnd_suspend_hw "device_t dev" +.Fn bhnd_suspend_hw "device_t dev" "uint16_t ioctl" .Ft bool .Fn bhnd_is_hw_suspended "device_t dev" .\" @@ -1054,7 +1054,10 @@ .Fa dev to a low power .Dq RESET -state. +state, writing +.Fa ioctl +to the I/O control flags of +.Fa dev . The hardware may be brought out of this state using .Fn bhnd_reset_hw . .Pp @@ -1062,10 +1065,14 @@ .Fn bhnd_reset_hw function first transitions the device .Fa dev -to a low power RESET state, and then brings the device out of RESET, writing +to a low power RESET state, writing +.Fa ioctl_reset +to the I/O control flags +of +.Fa dev , +and then brings the device out of RESET, writing .Fa ioctl -to the I/O control flags of -.Fa dev . +to the device's I/O control flags. .Pp The .Fn bhnd_is_hw_suspended Index: sys/dev/bhnd/bcma/bcma.c =================================================================== --- sys/dev/bhnd/bcma/bcma.c +++ sys/dev/bhnd/bcma/bcma.c @@ -296,22 +296,22 @@ } static int -bcma_reset_hw(device_t dev, device_t child, uint16_t ioctl) +bcma_reset_hw(device_t dev, device_t child, uint16_t ioctl, + uint16_t reset_ioctl) { - struct bcma_devinfo *dinfo; - struct bhnd_core_pmu_info *pm; - struct bhnd_resource *r; - int error; + struct bcma_devinfo *dinfo; + struct bhnd_resource *r; + uint16_t clkflags; + int error; if (device_get_parent(child) != dev) return (EINVAL); dinfo = device_get_ivars(child); - pm = dinfo->pmu_info; - /* We require exclusive control over BHND_IOCTL_CLK_EN and - * BHND_IOCTL_CLK_FORCE. */ - if (ioctl & (BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE)) + /* We require exclusive control over BHND_IOCTL_CLK_(EN|FORCE) */ + clkflags = BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE; + if (ioctl & clkflags) return (EINVAL); /* Can't suspend the core without access to the agent registers */ @@ -319,7 +319,7 @@ return (ENODEV); /* Place core into known RESET state */ - if ((error = BHND_BUS_SUSPEND_HW(dev, child))) + if ((error = bhnd_suspend_hw(child, reset_ioctl))) return (error); /* @@ -329,9 +329,7 @@ * - Force clock distribution to ensure propagation throughout the * core. */ - error = bhnd_write_ioctl(child, - ioctl | BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE, UINT16_MAX); - if (error) + if ((error = bhnd_write_ioctl(child, ioctl | clkflags, UINT16_MAX))) return (error); /* Bring the core out of reset */ @@ -347,11 +345,11 @@ } static int -bcma_suspend_hw(device_t dev, device_t child) +bcma_suspend_hw(device_t dev, device_t child, uint16_t ioctl) { struct bcma_devinfo *dinfo; struct bhnd_resource *r; - uint32_t rst; + uint16_t clkflags; int error; if (device_get_parent(child) != dev) @@ -359,6 +357,11 @@ dinfo = device_get_ivars(child); + /* We require exclusive control over BHND_IOCTL_CLK_(EN|FORCE) */ + clkflags = BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE; + if (ioctl & clkflags) + return (EINVAL); + /* Can't suspend the core without access to the agent registers */ if ((r = dinfo->res_agent) == NULL) return (ENODEV); @@ -367,17 +370,12 @@ if ((error = bcma_dmp_wait_reset(child, dinfo))) return (error); - /* Already in reset? */ - rst = bhnd_bus_read_4(r, BCMA_DMP_RESETCTRL); - if (rst & BCMA_DMP_RC_RESET) - return (0); - - /* Put core into reset */ + /* Put core into reset (if not already in reset) */ if ((error = bcma_dmp_write_reset(child, dinfo, BCMA_DMP_RC_RESET))) return (error); - /* Clear core flags */ - if ((error = bhnd_write_ioctl(child, 0x0, UINT16_MAX))) + /* Write core flags (and clear CLK_EN/CLK_FORCE) */ + if ((error = bhnd_write_ioctl(child, ioctl, ~clkflags))) return (error); return (0); Index: sys/dev/bhnd/bcma/bcma_subr.c =================================================================== --- sys/dev/bhnd/bcma/bcma_subr.c +++ sys/dev/bhnd/bcma/bcma_subr.c @@ -594,9 +594,16 @@ int bcma_dmp_write_reset(device_t child, struct bcma_devinfo *dinfo, uint32_t value) { + uint32_t rst; + if (dinfo->res_agent == NULL) return (ENODEV); + /* Already in requested reset state? */ + rst = bhnd_bus_read_4(dinfo->res_agent, BCMA_DMP_RESETCTRL); + if (rst == value) + return (0); + bhnd_bus_write_4(dinfo->res_agent, BCMA_DMP_RESETCTRL, value); bhnd_bus_read_4(dinfo->res_agent, BCMA_DMP_RESETCTRL); /* read-back */ DELAY(10); Index: sys/dev/bhnd/bhnd.h =================================================================== --- sys/dev/bhnd/bhnd.h +++ sys/dev/bhnd/bhnd.h @@ -818,23 +818,27 @@ } /** - * Place the bhnd(4) device's hardware into a reset state, and then bring the - * hardware out of reset with BHND_IOCTL_CLK_EN and @p ioctl flags set. + * Place the bhnd(4) device's hardware into a low-power RESET state with + * the @p reset_ioctl I/O control flags set, and then bring the hardware out of + * RESET with the @p ioctl I/O control flags set. * - * Any clock or resource PMU requests previously made by @p dev will be + * Any clock or resource PMU requests previously made by @p child will be * invalidated. * * @param dev The device to be reset. - * @param ioctl Device-specific core ioctl flags to be supplied on reset - * (see BHND_IOCTL_*). + * @param ioctl Device-specific I/O control flags to be set when bringing + * the core out of its RESET state (see BHND_IOCTL_*). + * @param reset_ioctl Device-specific I/O control flags to be set when placing + * the core into its RESET state. * * @retval 0 success * @retval non-zero error */ static inline int -bhnd_reset_hw(device_t dev, uint16_t ioctl) +bhnd_reset_hw(device_t dev, uint16_t ioctl, uint16_t reset_ioctl) { - return (BHND_BUS_RESET_HW(device_get_parent(dev), dev, ioctl)); + return (BHND_BUS_RESET_HW(device_get_parent(dev), dev, ioctl, + reset_ioctl)); } /** @@ -851,9 +855,9 @@ * @retval non-zero error */ static inline int -bhnd_suspend_hw(device_t dev) +bhnd_suspend_hw(device_t dev, uint16_t ioctl) { - return (BHND_BUS_SUSPEND_HW(device_get_parent(dev), dev)); + return (BHND_BUS_SUSPEND_HW(device_get_parent(dev), dev, ioctl)); } /** Index: sys/dev/bhnd/bhnd_bus_if.m =================================================================== --- sys/dev/bhnd/bhnd_bus_if.m +++ sys/dev/bhnd/bhnd_bus_if.m @@ -96,7 +96,8 @@ } static int - bhnd_bus_null_reset_hw(device_t dev, device_t child, uint16_t ioctl) + bhnd_bus_null_reset_hw(device_t dev, device_t child, uint16_t ioctl, + uint16_t reset_ioctl) { panic("bhnd_bus_reset_hw unimplemented"); } @@ -624,16 +625,19 @@ } DEFAULT bhnd_bus_null_is_hw_suspended; /** - * Place the bhnd(4) device's hardware into a reset state, and then bring the - * hardware out of reset with BHND_IOCTL_CLK_EN and @p ioctl flags set. + * Place the bhnd(4) device's hardware into a low-power RESET state with + * the @p reset_ioctl I/O control flags set, and then bring the hardware out of + * RESET with the @p ioctl I/O control flags set. * * Any clock or resource PMU requests previously made by @p child will be * invalidated. * * @param dev The bhnd bus parent of @p child. * @param child The device to be reset. - * @param ioctl Device-specific core ioctl flags to be supplied on reset - * (see BHND_IOCTL_*). + * @param ioctl Device-specific I/O control flags to be set when bringing + * the core out of its RESET state (see BHND_IOCTL_*). + * @param reset_ioctl Device-specific I/O control flags to be set when placing + * the core into its RESET state. * * @retval 0 success * @retval non-zero error @@ -642,18 +646,21 @@ device_t dev; device_t child; uint16_t ioctl; + uint16_t reset_ioctl; } DEFAULT bhnd_bus_null_reset_hw; /** - * Suspend @p child's hardware in a low-power reset state. + * Suspend @p child's hardware in a low-power RESET state. * * Any clock or resource PMU requests previously made by @p dev will be * invalidated. * - * The hardware may be brought out of reset via bhnd_reset_hw(). + * The hardware may be brought out of RESET via bhnd_reset_hw(). * * @param dev The bhnd bus parent of @p child. * @param dev The device to be suspended. + * @param ioctl Device-specific I/O control flags to be set when placing + * the core into its RESET state (see BHND_IOCTL_*). * * @retval 0 success * @retval non-zero error @@ -661,6 +668,7 @@ METHOD int suspend_hw { device_t dev; device_t child; + uint16_t ioctl; } DEFAULT bhnd_bus_null_suspend_hw; /** Index: sys/dev/bhnd/cores/usb/bhnd_usb.c =================================================================== --- sys/dev/bhnd/cores/usb/bhnd_usb.c +++ sys/dev/bhnd/cores/usb/bhnd_usb.c @@ -98,7 +98,7 @@ sc = device_get_softc(dev); - bhnd_reset_hw(dev, 0); + bhnd_reset_hw(dev, 0, 0); /* * Allocate the resources which the parent bus has already Index: sys/dev/bhnd/siba/siba.c =================================================================== --- sys/dev/bhnd/siba/siba.c +++ sys/dev/bhnd/siba/siba.c @@ -626,6 +626,10 @@ if (ts_low & SIBA_TML_RESET) return (true); + /* Is target reject enabled? */ + if (ts_low & SIBA_TML_REJ_MASK) + return (true); + /* Is core clocked? */ ioctl = SIBA_REG_GET(ts_low, TML_SICF); if (!(ioctl & BHND_IOCTL_CLK_EN)) @@ -635,11 +639,13 @@ } static int -siba_reset_hw(device_t dev, device_t child, uint16_t ioctl) +siba_reset_hw(device_t dev, device_t child, uint16_t ioctl, + uint16_t reset_ioctl) { struct siba_devinfo *dinfo; struct bhnd_resource *r; uint32_t ts_low, imstate; + uint16_t clkflags; int error; if (device_get_parent(child) != dev) @@ -651,19 +657,18 @@ if ((r = dinfo->cfg_res[0]) == NULL) return (ENODEV); - /* We require exclusive control over BHND_IOCTL_CLK_EN and - * BHND_IOCTL_CLK_FORCE. */ - if (ioctl & (BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE)) + /* We require exclusive control over BHND_IOCTL_CLK_(EN|FORCE) */ + clkflags = BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE; + if (ioctl & clkflags) return (EINVAL); /* Place core into known RESET state */ - if ((error = BHND_BUS_SUSPEND_HW(dev, child))) + if ((error = bhnd_suspend_hw(child, reset_ioctl))) return (error); /* Leaving the core in reset, set the caller's IOCTL flags and * enable the core's clocks. */ - ts_low = (ioctl | BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE) << - SIBA_TML_SICF_SHIFT; + ts_low = (ioctl | clkflags) << SIBA_TML_SICF_SHIFT; error = siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW, ts_low, SIBA_TML_SICF_MASK); if (error) @@ -704,13 +709,13 @@ } static int -siba_suspend_hw(device_t dev, device_t child) +siba_suspend_hw(device_t dev, device_t child, uint16_t ioctl) { struct siba_softc *sc; struct siba_devinfo *dinfo; struct bhnd_resource *r; uint32_t idl, ts_low; - uint16_t ioctl; + uint16_t cflags, clkflags; int error; if (device_get_parent(child) != dev) @@ -723,25 +728,34 @@ if ((r = dinfo->cfg_res[0]) == NULL) return (ENODEV); + /* We require exclusive control over BHND_IOCTL_CLK_(EN|FORCE) */ + clkflags = BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE; + if (ioctl & clkflags) + return (EINVAL); + /* Already in RESET? */ ts_low = bhnd_bus_read_4(r, SIBA_CFG0_TMSTATELOW); if (ts_low & SIBA_TML_RESET) { - /* Clear IOCTL flags, ensuring the clock is disabled */ - return (siba_write_target_state(child, dinfo, - SIBA_CFG0_TMSTATELOW, 0x0, SIBA_TML_SICF_MASK)); + /* Set the caller's IOCTL flags; this will clear + * CLK_EN/CLK_FORCE */ + ts_low = (ioctl << SIBA_TML_SICF_SHIFT); - return (0); + return (siba_write_target_state(child, dinfo, + SIBA_CFG0_TMSTATELOW, ts_low, SIBA_TML_SICF_MASK)); } /* If clocks are already disabled, we can put the core directly - * into RESET */ - ioctl = SIBA_REG_GET(ts_low, TML_SICF); - if (!(ioctl & BHND_IOCTL_CLK_EN)) { - /* Set RESET and clear IOCTL flags */ + * into RESET while setting the caller's IOCTL flags */ + cflags = SIBA_REG_GET(ts_low, TML_SICF); + if (!(cflags & BHND_IOCTL_CLK_EN)) { + /* Set RESET and the caller's IOCTL flags; this will + * leave CLK_EN/CLK_FORCE cleared */ + ts_low = SIBA_TML_RESET; + ts_low |= (ioctl << SIBA_TML_SICF_SHIFT); + return (siba_write_target_state(child, dinfo, - SIBA_CFG0_TMSTATELOW, - SIBA_TML_RESET, - SIBA_TML_RESET | SIBA_TML_SICF_MASK)); + SIBA_CFG0_TMSTATELOW, ts_low, + SIBA_TML_RESET|SIBA_TML_SICF_MASK)); } /* Reject any further target backplane transactions */ @@ -760,25 +774,25 @@ return (error); } - /* Put the core into RESET|REJECT, forcing clocks to ensure the RESET - * signal propagates throughout the core, leaving REJECT asserted. */ + /* Put the core into RESET|REJECT, setting the caller's IOCTL flags and + * forcing clocks to ensure the RESET signal propagates throughout the + * core, leaving REJECT asserted. */ ts_low = SIBA_TML_RESET; - ts_low |= (BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE) << - SIBA_TML_SICF_SHIFT; + ts_low |= (ioctl << SIBA_TML_SICF_SHIFT); + ts_low |= (clkflags << SIBA_TML_SICF_SHIFT); error = siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW, - ts_low, ts_low); + ts_low, SIBA_TML_RESET|SIBA_TML_SICF_MASK); if (error) return (error); /* Give RESET ample time */ DELAY(10); - /* Leaving core in reset, disable all clocks, clear REJ flags and - * IOCTL state */ + /* Leaving core in reset, disable all clocks, and clear REJ flags */ error = siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW, SIBA_TML_RESET, - SIBA_TML_RESET | SIBA_TML_REJ | SIBA_TML_SICF_MASK); + SIBA_TML_RESET | SIBA_TML_REJ | clkflags); if (error) return (error);