3636#define EXYNOS5_FSEL_26MHZ 0x6
3737#define EXYNOS5_FSEL_50MHZ 0x7
3838
39+ /* USB 3.2 DRD 4nm PHY link controller registers */
40+ #define EXYNOS2200_DRD_CLKRST 0x0c
41+ #define EXYNOS2200_CLKRST_LINK_PCLK_SEL BIT(1)
42+
43+ #define EXYNOS2200_DRD_UTMI 0x10
44+ #define EXYNOS2200_UTMI_FORCE_VBUSVALID BIT(1)
45+ #define EXYNOS2200_UTMI_FORCE_BVALID BIT(0)
46+
47+ #define EXYNOS2200_DRD_HSP_MISC 0x114
48+ #define HSP_MISC_SET_REQ_IN2 BIT(4)
49+ #define HSP_MISC_RES_TUNE GENMASK(1, 0)
50+ #define RES_TUNE_PHY1_PHY2 0x1
51+ #define RES_TUNE_PHY1 0x2
52+ #define RES_TUNE_PHY2 0x3
53+
3954/* Exynos5: USB 3.0 DRD PHY registers */
4055#define EXYNOS5_DRD_LINKSYSTEM 0x04
4156#define LINKSYSTEM_XHCI_VERSION_CONTROL BIT(27)
@@ -431,6 +446,7 @@ struct exynos5_usbdrd_phy_drvdata {
431446 * @clks: clocks for register access
432447 * @core_clks: core clocks for phy (ref, pipe3, utmi+, ITP, etc. as required)
433448 * @drv_data: pointer to SoC level driver data structure
449+ * @hs_phy: pointer to non-Samsung IP high-speed phy controller
434450 * @phy_mutex: mutex protecting phy_init/exit & TCPC callbacks
435451 * @phys: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY
436452 * instances each with its 'phy' and 'phy_cfg'.
@@ -448,6 +464,7 @@ struct exynos5_usbdrd_phy {
448464 struct clk_bulk_data * clks ;
449465 struct clk_bulk_data * core_clks ;
450466 const struct exynos5_usbdrd_phy_drvdata * drv_data ;
467+ struct phy * hs_phy ;
451468 struct mutex phy_mutex ;
452469 struct phy_usb_instance {
453470 struct phy * phy ;
@@ -1285,6 +1302,149 @@ static const struct phy_ops exynos7870_usbdrd_phy_ops = {
12851302 .owner = THIS_MODULE ,
12861303};
12871304
1305+ static void exynos2200_usbdrd_utmi_init (struct exynos5_usbdrd_phy * phy_drd )
1306+ {
1307+ /* Configure non-Samsung IP PHY, responsible for UTMI */
1308+ phy_init (phy_drd -> hs_phy );
1309+ }
1310+
1311+ static void exynos2200_usbdrd_link_init (struct exynos5_usbdrd_phy * phy_drd )
1312+ {
1313+ void __iomem * regs_base = phy_drd -> reg_phy ;
1314+ u32 reg ;
1315+
1316+ /*
1317+ * Disable HWACG (hardware auto clock gating control). This will force
1318+ * QACTIVE signal in Q-Channel interface to HIGH level, to make sure
1319+ * the PHY clock is not gated by the hardware.
1320+ */
1321+ reg = readl (regs_base + EXYNOS850_DRD_LINKCTRL );
1322+ reg |= LINKCTRL_FORCE_QACT ;
1323+ writel (reg , regs_base + EXYNOS850_DRD_LINKCTRL );
1324+
1325+ /* De-assert link reset */
1326+ reg = readl (regs_base + EXYNOS2200_DRD_CLKRST );
1327+ reg &= ~CLKRST_LINK_SW_RST ;
1328+ writel (reg , regs_base + EXYNOS2200_DRD_CLKRST );
1329+
1330+ /* Set link VBUS Valid */
1331+ reg = readl (regs_base + EXYNOS2200_DRD_UTMI );
1332+ reg |= EXYNOS2200_UTMI_FORCE_BVALID | EXYNOS2200_UTMI_FORCE_VBUSVALID ;
1333+ writel (reg , regs_base + EXYNOS2200_DRD_UTMI );
1334+ }
1335+
1336+ static void
1337+ exynos2200_usbdrd_link_attach_detach_pipe3_phy (struct phy_usb_instance * inst )
1338+ {
1339+ struct exynos5_usbdrd_phy * phy_drd = to_usbdrd_phy (inst );
1340+ void __iomem * regs_base = phy_drd -> reg_phy ;
1341+ u32 reg ;
1342+
1343+ reg = readl (regs_base + EXYNOS850_DRD_LINKCTRL );
1344+ if (inst -> phy_cfg -> id == EXYNOS5_DRDPHY_UTMI ) {
1345+ /* force pipe3 signal for link */
1346+ reg &= ~LINKCTRL_FORCE_PHYSTATUS ;
1347+ reg |= LINKCTRL_FORCE_PIPE_EN | LINKCTRL_FORCE_RXELECIDLE ;
1348+ } else {
1349+ /* disable forcing pipe interface */
1350+ reg &= ~LINKCTRL_FORCE_PIPE_EN ;
1351+ }
1352+ writel (reg , regs_base + EXYNOS850_DRD_LINKCTRL );
1353+
1354+ reg = readl (regs_base + EXYNOS2200_DRD_HSP_MISC );
1355+ if (inst -> phy_cfg -> id == EXYNOS5_DRDPHY_UTMI ) {
1356+ /* calibrate only eUSB phy */
1357+ reg |= FIELD_PREP (HSP_MISC_RES_TUNE , RES_TUNE_PHY1 );
1358+ reg |= HSP_MISC_SET_REQ_IN2 ;
1359+ } else {
1360+ /* calibrate for dual phy */
1361+ reg |= FIELD_PREP (HSP_MISC_RES_TUNE , RES_TUNE_PHY1_PHY2 );
1362+ reg &= ~HSP_MISC_SET_REQ_IN2 ;
1363+ }
1364+ writel (reg , regs_base + EXYNOS2200_DRD_HSP_MISC );
1365+
1366+ reg = readl (regs_base + EXYNOS2200_DRD_CLKRST );
1367+ if (inst -> phy_cfg -> id == EXYNOS5_DRDPHY_UTMI )
1368+ reg &= ~EXYNOS2200_CLKRST_LINK_PCLK_SEL ;
1369+ else
1370+ reg |= EXYNOS2200_CLKRST_LINK_PCLK_SEL ;
1371+
1372+ writel (reg , regs_base + EXYNOS2200_DRD_CLKRST );
1373+ }
1374+
1375+ static int exynos2200_usbdrd_phy_init (struct phy * phy )
1376+ {
1377+ struct phy_usb_instance * inst = phy_get_drvdata (phy );
1378+ struct exynos5_usbdrd_phy * phy_drd = to_usbdrd_phy (inst );
1379+ int ret ;
1380+
1381+ if (inst -> phy_cfg -> id == EXYNOS5_DRDPHY_UTMI ) {
1382+ /* Power-on PHY ... */
1383+ ret = regulator_bulk_enable (phy_drd -> drv_data -> n_regulators ,
1384+ phy_drd -> regulators );
1385+ if (ret ) {
1386+ dev_err (phy_drd -> dev ,
1387+ "Failed to enable PHY regulator(s)\n" );
1388+ return ret ;
1389+ }
1390+ }
1391+ /*
1392+ * ... and ungate power via PMU. Without this here, we get an SError
1393+ * trying to access PMA registers
1394+ */
1395+ exynos5_usbdrd_phy_isol (inst , false);
1396+
1397+ ret = clk_bulk_prepare_enable (phy_drd -> drv_data -> n_clks , phy_drd -> clks );
1398+ if (ret )
1399+ return ret ;
1400+
1401+ /* Set up the link controller */
1402+ exynos2200_usbdrd_link_init (phy_drd );
1403+
1404+ /* UTMI or PIPE3 link preparation */
1405+ exynos2200_usbdrd_link_attach_detach_pipe3_phy (inst );
1406+
1407+ /* UTMI or PIPE3 specific init */
1408+ inst -> phy_cfg -> phy_init (phy_drd );
1409+
1410+ clk_bulk_disable_unprepare (phy_drd -> drv_data -> n_clks , phy_drd -> clks );
1411+
1412+ return 0 ;
1413+ }
1414+
1415+ static int exynos2200_usbdrd_phy_exit (struct phy * phy )
1416+ {
1417+ struct phy_usb_instance * inst = phy_get_drvdata (phy );
1418+ struct exynos5_usbdrd_phy * phy_drd = to_usbdrd_phy (inst );
1419+ void __iomem * regs_base = phy_drd -> reg_phy ;
1420+ u32 reg ;
1421+ int ret ;
1422+
1423+ ret = clk_bulk_prepare_enable (phy_drd -> drv_data -> n_clks , phy_drd -> clks );
1424+ if (ret )
1425+ return ret ;
1426+
1427+ reg = readl (regs_base + EXYNOS2200_DRD_UTMI );
1428+ reg &= ~(EXYNOS2200_UTMI_FORCE_BVALID | EXYNOS2200_UTMI_FORCE_VBUSVALID );
1429+ writel (reg , regs_base + EXYNOS2200_DRD_UTMI );
1430+
1431+ reg = readl (regs_base + EXYNOS2200_DRD_CLKRST );
1432+ reg |= CLKRST_LINK_SW_RST ;
1433+ writel (reg , regs_base + EXYNOS2200_DRD_CLKRST );
1434+
1435+ clk_bulk_disable_unprepare (phy_drd -> drv_data -> n_clks , phy_drd -> clks );
1436+
1437+ exynos5_usbdrd_phy_isol (inst , true);
1438+ return regulator_bulk_disable (phy_drd -> drv_data -> n_regulators ,
1439+ phy_drd -> regulators );
1440+ }
1441+
1442+ static const struct phy_ops exynos2200_usbdrd_phy_ops = {
1443+ .init = exynos2200_usbdrd_phy_init ,
1444+ .exit = exynos2200_usbdrd_phy_exit ,
1445+ .owner = THIS_MODULE ,
1446+ };
1447+
12881448static void
12891449exynos5_usbdrd_usb_v3p1_pipe_override (struct exynos5_usbdrd_phy * phy_drd )
12901450{
@@ -1594,27 +1754,37 @@ static int exynos5_usbdrd_phy_clk_handle(struct exynos5_usbdrd_phy *phy_drd)
15941754 return dev_err_probe (phy_drd -> dev , ret ,
15951755 "failed to get phy core clock(s)\n" );
15961756
1597- ref_clk = NULL ;
1598- for (int i = 0 ; i < phy_drd -> drv_data -> n_core_clks ; ++ i ) {
1599- if (!strcmp (phy_drd -> core_clks [i ].id , "ref" )) {
1600- ref_clk = phy_drd -> core_clks [i ].clk ;
1601- break ;
1757+ if (phy_drd -> drv_data -> n_core_clks ) {
1758+ ref_clk = NULL ;
1759+ for (int i = 0 ; i < phy_drd -> drv_data -> n_core_clks ; ++ i ) {
1760+ if (!strcmp (phy_drd -> core_clks [i ].id , "ref" )) {
1761+ ref_clk = phy_drd -> core_clks [i ].clk ;
1762+ break ;
1763+ }
16021764 }
1603- }
1604- if (!ref_clk )
1605- return dev_err_probe (phy_drd -> dev , - ENODEV ,
1606- "failed to find phy reference clock\n" );
1765+ if (!ref_clk )
1766+ return dev_err_probe (phy_drd -> dev , - ENODEV ,
1767+ "failed to find phy reference clock\n" );
16071768
1608- ref_rate = clk_get_rate (ref_clk );
1609- ret = exynos5_rate_to_clk (ref_rate , & phy_drd -> extrefclk );
1610- if (ret )
1611- return dev_err_probe (phy_drd -> dev , ret ,
1612- "clock rate (%ld) not supported\n" ,
1613- ref_rate );
1769+ ref_rate = clk_get_rate (ref_clk );
1770+ ret = exynos5_rate_to_clk (ref_rate , & phy_drd -> extrefclk );
1771+ if (ret )
1772+ return dev_err_probe (phy_drd -> dev , ret ,
1773+ "clock rate (%ld) not supported\n" ,
1774+ ref_rate );
1775+ }
16141776
16151777 return 0 ;
16161778}
16171779
1780+ static const struct exynos5_usbdrd_phy_config phy_cfg_exynos2200 [] = {
1781+ {
1782+ .id = EXYNOS5_DRDPHY_UTMI ,
1783+ .phy_isol = exynos5_usbdrd_phy_isol ,
1784+ .phy_init = exynos2200_usbdrd_utmi_init ,
1785+ },
1786+ };
1787+
16181788static int exynos5_usbdrd_orien_sw_set (struct typec_switch_dev * sw ,
16191789 enum typec_orientation orientation )
16201790{
@@ -1767,6 +1937,19 @@ static const char * const exynos5_regulator_names[] = {
17671937 "vbus" , "vbus-boost" ,
17681938};
17691939
1940+ static const struct exynos5_usbdrd_phy_drvdata exynos2200_usb32drd_phy = {
1941+ .phy_cfg = phy_cfg_exynos2200 ,
1942+ .phy_ops = & exynos2200_usbdrd_phy_ops ,
1943+ .pmu_offset_usbdrd0_phy = EXYNOS2200_PHY_CTRL_USB20 ,
1944+ .clk_names = exynos5_clk_names ,
1945+ .n_clks = ARRAY_SIZE (exynos5_clk_names ),
1946+ /* clocks and regulators are specific to the underlying PHY blocks */
1947+ .core_clk_names = NULL ,
1948+ .n_core_clks = 0 ,
1949+ .regulator_names = NULL ,
1950+ .n_regulators = 0 ,
1951+ };
1952+
17701953static const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = {
17711954 .phy_cfg = phy_cfg_exynos5 ,
17721955 .phy_ops = & exynos5_usbdrd_phy_ops ,
@@ -2024,6 +2207,9 @@ static const struct of_device_id exynos5_usbdrd_phy_of_match[] = {
20242207 {
20252208 .compatible = "google,gs101-usb31drd-phy" ,
20262209 .data = & gs101_usbd31rd_phy
2210+ }, {
2211+ .compatible = "samsung,exynos2200-usb32drd-phy" ,
2212+ .data = & exynos2200_usb32drd_phy ,
20272213 }, {
20282214 .compatible = "samsung,exynos5250-usbdrd-phy" ,
20292215 .data = & exynos5250_usbdrd_phy
@@ -2099,6 +2285,17 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
20992285 return PTR_ERR (phy_drd -> reg_phy );
21002286 }
21012287
2288+ /*
2289+ * USB32DRD 4nm controller implements Synopsys eUSB2.0 PHY
2290+ * and Synopsys SS/USBDP COMBOPHY, managed by external code.
2291+ */
2292+ if (of_property_present (dev -> of_node , "phy-names" )) {
2293+ phy_drd -> hs_phy = devm_of_phy_get (dev , dev -> of_node , "hs" );
2294+ if (IS_ERR (phy_drd -> hs_phy ))
2295+ return dev_err_probe (dev , PTR_ERR (phy_drd -> hs_phy ),
2296+ "failed to get hs_phy\n" );
2297+ }
2298+
21022299 ret = exynos5_usbdrd_phy_clk_handle (phy_drd );
21032300 if (ret )
21042301 return ret ;
0 commit comments