1 .. SPDX-License-Identifier: GPL-2.0 1 .. SPDX-License-Identifier: GPL-2.0 2 .. include:: ../../disclaimer-zh_CN.rst 2 .. include:: ../../disclaimer-zh_CN.rst 3 3 4 :Original: Documentation/driver-api/phy/phy.rs 4 :Original: Documentation/driver-api/phy/phy.rst 5 5 6 :翻译: 6 :翻译: 7 7 8 司延腾 Yanteng Si <siyanteng@loongson.cn> 8 司延腾 Yanteng Si <siyanteng@loongson.cn> 9 9 10 ========= 10 ========= 11 PHY子系统 11 PHY子系统 12 ========= 12 ========= 13 13 14 :作者: Kishon Vijay Abraham I <kishon@ti.com> 14 :作者: Kishon Vijay Abraham I <kishon@ti.com> 15 15 16 本文档解释了 PHY 的通用框架和提 16 本文档解释了 PHY 的通用框架和提供的API,以及使用方法。 17 17 18 简介 18 简介 19 ==== 19 ==== 20 20 21 *PHY* 是物理层的缩写,它被用来把 21 *PHY* 是物理层的缩写,它被用来把设备连接到一个物理媒介,例如USB控制器 22 有一个提供序列化、反序列化、编 22 有一个提供序列化、反序列化、编码、解码和负责获取所需的数据传输速率的 PHY。 23 注意,有些USB控制器内嵌了 PHY 的 23 注意,有些USB控制器内嵌了 PHY 的功能,其它的则使用了一个外置的PHY,此外 24 使用 PHY 的设备还有无线网、以太 24 使用 PHY 的设备还有无线网、以太网、SATA等(控制器)。 25 25 26 创建这个框架的目的是将遍布 Linux 26 创建这个框架的目的是将遍布 Linux 内核的 PHY 驱动程序融入到 drivers/phy, 27 以增加代码的可复用性,进而提高 27 以增加代码的可复用性,进而提高代码的可维护性。 28 28 29 该框架仅适用于使用外部 PHY(PHY 29 该框架仅适用于使用外部 PHY(PHY 功能未嵌入控制器内)的设备。 30 30 31 注册/注销PHY provider 31 注册/注销PHY provider 32 ===================== 32 ===================== 33 33 34 PHY provider是指实现一个或多个 PHY 34 PHY provider是指实现一个或多个 PHY 实例的实体。对于 PHY provider 仅 35 实现单个 PHY 实例的简单情况,框 35 实现单个 PHY 实例的简单情况,框架在 of_phy_simple_xlate 中提供其自己 36 的 of_xlate 实现。如果 PHY provider 实 36 的 of_xlate 实现。如果 PHY provider 实现多个实例,则应提供其自己的 37 of_xlate 实现。of_xlate 仅用于 dt 启动 37 of_xlate 实现。of_xlate 仅用于 dt 启动情况。 38 38 39 :: 39 :: 40 40 41 #define of_phy_provider_register(dev, 41 #define of_phy_provider_register(dev, xlate) \ 42 __of_phy_provider_register((de 42 __of_phy_provider_register((dev), NULL, THIS_MODULE, (xlate)) 43 43 44 #define devm_of_phy_provider_register( 44 #define devm_of_phy_provider_register(dev, xlate) \ 45 __devm_of_phy_provider_registe 45 __devm_of_phy_provider_register((dev), NULL, THIS_MODULE, 46 46 (xlate)) 47 47 48 of_phy_provider_register 和 devm_of_phy_provi 48 of_phy_provider_register 和 devm_of_phy_provider_register 宏 49 可用于注册 phy_provider,它以 device 49 可用于注册 phy_provider,它以 device 和 of_xlate 作为参数。对于 dt 50 启动情况,所有 PHY provider 都应使 50 启动情况,所有 PHY provider 都应使用上述两个宏之一来注册 PHY provider。 51 51 52 与 PHY provider 关联的设备树节点通 52 与 PHY provider 关联的设备树节点通常包含一组子节点,每个子节点代表一个 53 PHY。某些绑定可能会为了上下文和 53 PHY。某些绑定可能会为了上下文和可扩展性将子节点嵌套在特别的层级中,在这种 54 情况下,可以使用低级别的 of_phy_pr 54 情况下,可以使用低级别的 of_phy_provider_register_full() 和 55 devm_of_phy_provider_register_full() 宏来覆 55 devm_of_phy_provider_register_full() 宏来覆盖包含子节点的节点。 56 56 57 :: 57 :: 58 58 59 #define of_phy_provider_register_full( 59 #define of_phy_provider_register_full(dev, children, xlate) \ 60 __of_phy_provider_register(dev 60 __of_phy_provider_register(dev, children, THIS_MODULE, xlate) 61 61 62 #define devm_of_phy_provider_register_ 62 #define devm_of_phy_provider_register_full(dev, children, xlate) \ 63 __devm_of_phy_provider_registe 63 __devm_of_phy_provider_register_full(dev, children, 64 64 THIS_MODULE, xlate) 65 65 66 void devm_of_phy_provider_unregister(s 66 void devm_of_phy_provider_unregister(struct device *dev, 67 struct phy_provider *phy_provi 67 struct phy_provider *phy_provider); 68 void of_phy_provider_unregister(struct 68 void of_phy_provider_unregister(struct phy_provider *phy_provider); 69 69 70 devm_of_phy_provider_unregister 和 of_phy_pro 70 devm_of_phy_provider_unregister 和 of_phy_provider_unregister 71 可以被用来注销PHY. 71 可以被用来注销PHY. 72 72 73 创建PHY 73 创建PHY 74 ======= 74 ======= 75 75 76 PHY 驱动程序应创建 PHY,以便其他 76 PHY 驱动程序应创建 PHY,以便其他外围(芯片)控制器能够使用它。PHY 框架 77 提供了 2 个 API 来创建 PHY。 77 提供了 2 个 API 来创建 PHY。 78 78 79 :: 79 :: 80 80 81 struct phy *phy_create(struct device * 81 struct phy *phy_create(struct device *dev, struct device_node *node, 82 const struct ph 82 const struct phy_ops *ops); 83 struct phy *devm_phy_create(struct dev 83 struct phy *devm_phy_create(struct device *dev, 84 struct dev 84 struct device_node *node, 85 const stru 85 const struct phy_ops *ops); 86 86 87 PHY 驱动程序可以使用上述两个 API 87 PHY 驱动程序可以使用上述两个 API 之一,通过传递设备指针和 phy_ops 88 来创建 PHY。 88 来创建 PHY。 89 89 90 phy_ops 是一组用于执行 PHY 操作(例 90 phy_ops 是一组用于执行 PHY 操作(例如 init、exit、power_on 和 91 power_off)的函数指针。 91 power_off)的函数指针。 92 92 93 在 phy_ops 中,PHY provider驱动程序在 93 在 phy_ops 中,PHY provider驱动程序在创建 PHY 后使用 phy_set_drvdata() 94 设置私有数据,使用 phy_get_drvdata() 94 设置私有数据,使用 phy_get_drvdata() 获取私有数据。 95 95 96 获取对 PHY 的引用 96 获取对 PHY 的引用 97 ================= 97 ================= 98 98 99 控制器必须先获取对 PHY 的引用, 99 控制器必须先获取对 PHY 的引用,然后才能使用 PHY。此框架提供以下 API 100 来获取对 PHY 的引用。 100 来获取对 PHY 的引用。 101 101 102 :: 102 :: 103 103 104 struct phy *phy_get(struct device *dev 104 struct phy *phy_get(struct device *dev, const char *string); 105 struct phy *devm_phy_get(struct device 105 struct phy *devm_phy_get(struct device *dev, const char *string); 106 struct phy *devm_phy_optional_get(stru 106 struct phy *devm_phy_optional_get(struct device *dev, 107 cons 107 const char *string); 108 struct phy *devm_of_phy_get(struct dev 108 struct phy *devm_of_phy_get(struct device *dev, struct device_node *np, 109 const char 109 const char *con_id); 110 struct phy *devm_of_phy_optional_get(s 110 struct phy *devm_of_phy_optional_get(struct device *dev, 111 s 111 struct device_node *np, 112 c 112 const char *con_id); 113 struct phy *devm_of_phy_get_by_index(s 113 struct phy *devm_of_phy_get_by_index(struct device *dev, 114 s 114 struct device_node *np, 115 i 115 int index); 116 116 117 phy_get、devm_phy_get 和 devm_phy_optional_g 117 phy_get、devm_phy_get 和 devm_phy_optional_get 可用于在 dt 118 启动的情况下获取 PHY,字符串参数 118 启动的情况下获取 PHY,字符串参数应包含 dt 数据中给出的 phy 名称,在 119 非 dt 启动的情况下,它应包含 PHY 119 非 dt 启动的情况下,它应包含 PHY 的标签。两个 devm_phy_get 在成功 120 获取 PHY 后使用 devres 将设备与 PHY 120 获取 PHY 后使用 devres 将设备与 PHY 关联。在驱动程序分离时,将在 121 devres 数据上调用 release 函数并释放 121 devres 数据上调用 release 函数并释放 devres 数据。当 phy 是可选 122 的时,应使用 _optional_get 变体。这 122 的时,应使用 _optional_get 变体。这些函数永远不会返回 -ENODEV,而 123 是在找不到 phy 时返回 NULL。一些通 123 是在找不到 phy 时返回 NULL。一些通用驱动程序(例如 ehci)可能使用 124 多个 phy。在这种情况下,devm_of_phy_ 124 多个 phy。在这种情况下,devm_of_phy_get 或 devm_of_phy_get_by_index 125 用于根据名称或索引获取 phy 引用 125 用于根据名称或索引获取 phy 引用。 126 126 127 需要注意的是,NULL 是有效的 phy 引 127 需要注意的是,NULL 是有效的 phy 引用。NULL phy 上的所有 phy 使用 128 者调用都将成为 NOP。也就是说释放 128 者调用都将成为 NOP。也就是说释放调用,当应用于 NULL phy 时,release 129 调用、phy_init()/phy_exit() 调用、phy_po 129 调用、phy_init()/phy_exit() 调用、phy_power_on()/phy_power_off() 130 调用都是 NOP。NULL phy 在处理可选的 130 调用都是 NOP。NULL phy 在处理可选的 phy 设备中很有用。 131 131 132 API的调用顺序 132 API的调用顺序 133 ============= 133 ============= 134 134 135 通常,调用顺序应该是:: 135 通常,调用顺序应该是:: 136 136 137 [devm_][of_]phy_get() 137 [devm_][of_]phy_get() 138 phy_init() 138 phy_init() 139 phy_power_on() 139 phy_power_on() 140 [phy_set_mode[_ext]()] 140 [phy_set_mode[_ext]()] 141 ... 141 ... 142 phy_power_off() 142 phy_power_off() 143 phy_exit() 143 phy_exit() 144 [[of_]phy_put()] 144 [[of_]phy_put()] 145 145 146 一些PHY驱动可能没有实现 :c:func:`phy 146 一些PHY驱动可能没有实现 :c:func:`phy_init` 或 :c:func:`phy_power_on`, 147 但是控制器应该总是调用这些函数 147 但是控制器应该总是调用这些函数以兼容其它PHY,有些PHY可能要求 148 :c:func:`phy_set_mode <phy_set_mode_ext>` 而 148 :c:func:`phy_set_mode <phy_set_mode_ext>` 而其他 PHY 可能使用 149 默认模式(通常通过设备树或其他 149 默认模式(通常通过设备树或其他固件配置)。出于兼容性考虑,如果您知道将 150 使用哪种模式,则应始终调用此函 150 使用哪种模式,则应始终调用此函数。通常,应在 :c:func:`phy_power_on` 151 之后调用此函数,尽管某些 PHY 驱 151 之后调用此函数,尽管某些 PHY 驱动程序可能随时允许调用它。 152 152 153 释放对 PHY 的引用 153 释放对 PHY 的引用 154 ================= 154 ================= 155 155 156 当控制器不再需要 PHY 时,它必须 156 当控制器不再需要 PHY 时,它必须使用上一节中提到的 API 释放对已获得 157 的 PHY 的引用。PHY 框架提供了 2 个 157 的 PHY 的引用。PHY 框架提供了 2 个 API 来释放对 PHY 的引用。 158 158 159 :: 159 :: 160 160 161 void phy_put(struct phy *phy); 161 void phy_put(struct phy *phy); 162 void devm_phy_put(struct device *dev, 162 void devm_phy_put(struct device *dev, struct phy *phy); 163 163 164 这两个 API 都用于释放对 PHY 的引用 164 这两个 API 都用于释放对 PHY 的引用,并且 devm_phy_put 会销毁与此 165 PHY 关联的设备资源。 165 PHY 关联的设备资源。 166 166 167 销毁 PHY 167 销毁 PHY 168 ======== 168 ======== 169 169 170 当创建 PHY 的驱动程序被卸载时, 170 当创建 PHY 的驱动程序被卸载时,它应该使用以下 2 个 API 之一销毁其创 171 建的 PHY:: 171 建的 PHY:: 172 172 173 void phy_destroy(struct phy *phy); 173 void phy_destroy(struct phy *phy); 174 void devm_phy_destroy(struct device *d 174 void devm_phy_destroy(struct device *dev, struct phy *phy); 175 175 176 这两个 API 都会销毁 PHY,并且 devm_p 176 这两个 API 都会销毁 PHY,并且 devm_phy_destroy 会销毁与此 PHY 关 177 联的 devres。 177 联的 devres。 178 178 179 PM Runtime 179 PM Runtime 180 ========== 180 ========== 181 181 182 这个子系统启用了pm runtime。 所以 182 这个子系统启用了pm runtime。 所以,在创建PHY 时,将调用此子系统创建的 183 phy 设备的 pm_runtime_enable 函数,在 183 phy 设备的 pm_runtime_enable 函数,在销毁 PHY 时,将调用 184 pm_runtime_disable。请注意,此子系统 184 pm_runtime_disable。请注意,此子系统创建的 phy 设备将是调用 phy_create 185 (PHY provider 设备)的设备的子设备 185 (PHY provider 设备)的设备的子设备。 186 186 187 因此,由于父子关系,此子系统创 187 因此,由于父子关系,此子系统创建的 phy_device 的 pm_runtime_get_sync 188 调用 PHY provider 设备的 pm_runtime_get_s 188 调用 PHY provider 设备的 pm_runtime_get_sync。还应注意, 189 phy_power_on 和 phy_power_off 分别执行 ph 189 phy_power_on 和 phy_power_off 分别执行 phy_pm_runtime_get_sync 和 190 phy_pm_runtime_put。有导出的 API,如 ph 190 phy_pm_runtime_put。有导出的 API,如 phy_pm_runtime_get、 191 phy_pm_runtime_get_sync、phy_pm_runtime_put 191 phy_pm_runtime_get_sync、phy_pm_runtime_put、phy_pm_runtime_put_sync、 192 phy_pm_runtime_allow 和 phy_pm_runtime_forbid 192 phy_pm_runtime_allow 和 phy_pm_runtime_forbid,用于执行 PM 操作。 193 193 194 PHY映射 194 PHY映射 195 ======= 195 ======= 196 196 197 为了在没有 DeviceTree 帮助的情况下 197 为了在没有 DeviceTree 帮助的情况下获取对 PHY 的引用,框架提供了可与 198 clkdev 进行比较的查找,允许将 clk 198 clkdev 进行比较的查找,允许将 clk 结构体绑定到设备。当 struct phy 的 199 句柄已存在时,可以在运行时进行 199 句柄已存在时,可以在运行时进行查找。 200 200 201 该框架提供以下 API 用于注册和注 201 该框架提供以下 API 用于注册和注销查找:: 202 202 203 int phy_create_lookup(struct phy *phy, 203 int phy_create_lookup(struct phy *phy, const char *con_id, 204 const char *dev_ 204 const char *dev_id); 205 void phy_remove_lookup(struct phy *phy 205 void phy_remove_lookup(struct phy *phy, const char *con_id, 206 const char *dev 206 const char *dev_id); 207 207 208 DeviceTree绑定 208 DeviceTree绑定 209 ============== 209 ============== 210 210 211 PHY dt 绑定的文档可以在以下位置找 211 PHY dt 绑定的文档可以在以下位置找到 @ 212 Documentation/devicetree/bindings/phy/phy-bind 212 Documentation/devicetree/bindings/phy/phy-bindings.txt
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.