Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: cdns3-ti: run HW init at resume() if HW was reset

At runtime_resume(), read the W1 (Wrapper Register 1) register to detect
if an hardware reset occurred. If it did, run the hardware init sequence.

This callback will be called at system-wide resume. Previously, if a
reset occurred during suspend, we would crash. The wrapper config had
not been written, leading to invalid register accesses inside cdns3.

Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com>
Link: https://lore.kernel.org/r/20250205-s2r-cdns-v7-6-13658a271c3c@bootlin.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Théo Lebrun and committed by
Greg Kroah-Hartman
9925aa4b 24346dc2

+25
+25
drivers/usb/cdns3/cdns3-ti.c
··· 186 186 data->vbus_divider = device_property_read_bool(dev, "ti,vbus-divider"); 187 187 data->usb2_only = device_property_read_bool(dev, "ti,usb2-only"); 188 188 189 + /* 190 + * The call below to pm_runtime_get_sync() MIGHT reset hardware, if it 191 + * detects it as uninitialised. We want to enforce a reset at probe, 192 + * and so do it manually here. This means the first runtime_resume() 193 + * will be a no-op. 194 + */ 189 195 cdns_ti_reset_and_init_hw(data); 190 196 191 197 pm_runtime_enable(dev); ··· 236 230 platform_set_drvdata(pdev, NULL); 237 231 } 238 232 233 + static int cdns_ti_runtime_resume(struct device *dev) 234 + { 235 + const u32 mask = USBSS_W1_PWRUP_RST | USBSS_W1_MODESTRAP_SEL; 236 + struct cdns_ti *data = dev_get_drvdata(dev); 237 + u32 w1; 238 + 239 + w1 = cdns_ti_readl(data, USBSS_W1); 240 + if ((w1 & mask) != mask) 241 + cdns_ti_reset_and_init_hw(data); 242 + 243 + return 0; 244 + } 245 + 246 + static const struct dev_pm_ops cdns_ti_pm_ops = { 247 + RUNTIME_PM_OPS(NULL, cdns_ti_runtime_resume, NULL) 248 + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) 249 + }; 250 + 239 251 static const struct of_device_id cdns_ti_of_match[] = { 240 252 { .compatible = "ti,j721e-usb", }, 241 253 { .compatible = "ti,am64-usb", }, ··· 267 243 .driver = { 268 244 .name = "cdns3-ti", 269 245 .of_match_table = cdns_ti_of_match, 246 + .pm = pm_ptr(&cdns_ti_pm_ops), 270 247 }, 271 248 }; 272 249