요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
=============
PHY subsystem
=============
:Author: Kishon Vijay Abraham I <[email protected]>
This document explains the Generic PHY Framework along with the APIs provided,
and how-to-use.
Introduction
============
*PHY* is the abbreviation for physical layer. It is used to connect a device
to the physical medium e.g., the USB controller has a PHY to provide functions
such as serialization, de-serialization, encoding, decoding and is responsible
for obtaining the required data transmission rate. Note that some USB
controllers have PHY functionality embedded into it and others use an external
PHY. Other peripherals that use PHY include Wireless LAN, Ethernet,
SATA etc.
The intention of creating this framework is to bring the PHY drivers spread
all over the Linux kernel to drivers/phy to increase code re-use and for
better code maintainability.
This framework will be of use only to devices that use external PHY (PHY
functionality is not embedded within the controller).
Registering/Unregistering the PHY provider
==========================================
PHY provider refers to an entity that implements one or more PHY instances.
For the simple case where the PHY provider implements only a single instance of
the PHY, the framework provides its own implementation of of_xlate in
of_phy_simple_xlate. If the PHY provider implements multiple instances, it
should provide its own implementation of of_xlate. of_xlate is used only for
dt boot case.
::
#define of_phy_provider_register(dev, xlate) \
__of_phy_provider_register((dev), NULL, THIS_MODULE, (xlate))
#define devm_of_phy_provider_register(dev, xlate) \
__devm_of_phy_provider_register((dev), NULL, THIS_MODULE,
(xlate))
of_phy_provider_register and devm_of_phy_provider_register macros can be used to
register the phy_provider and it takes device and of_xlate as
arguments. For the dt boot case, all PHY providers should use one of the above
2 macros to register the PHY provider.
Often the device tree nodes associated with a PHY provider will contain a set
of children that each represent a single PHY. Some bindings may nest the child
nodes within extra levels for context and extensibility, in which case the low
level of_phy_provider_register_full() and devm_of_phy_provider_register_full()
macros can be used to override the node containing the children.
::
#define of_phy_provider_register_full(dev, children, xlate) \
__of_phy_provider_register(dev, children, THIS_MODULE, xlate)
#define devm_of_phy_provider_register_full(dev, children, xlate) \
__devm_of_phy_provider_register_full(dev, children,
THIS_MODULE, xlate)
void devm_of_phy_provider_unregister(struct device *dev,
struct phy_provider *phy_provider);
void of_phy_provider_unregister(struct phy_provider *phy_provider);
devm_of_phy_provider_unregister and of_phy_provider_unregister can be used to
unregister the PHY.
Creating the PHY
================
The PHY driver should create the PHY in order for other peripheral controllers
to make use of it. The PHY framework provides 2 APIs to create the PHY.
::
struct phy *phy_create(struct device *dev, struct device_node *node,
const struct phy_ops *ops);
struct phy *devm_phy_create(struct device *dev,
struct device_node *node,
const struct phy_ops *ops);
The PHY drivers can use one of the above 2 APIs to create the PHY by passing
the device pointer and phy ops.
phy_ops is a set of function pointers for performing PHY operations such as
init, exit, power_on and power_off.
Inorder to dereference the private data (in phy_ops), the phy provider driver
can use phy_set_drvdata() after creating the PHY and use phy_get_drvdata() in
phy_ops to get back the private data.
Getting a reference to the PHY
==============================
Before the controller can make use of the PHY, it has to get a reference to
it. This framework provides the following APIs to get a reference to the PHY.
::
struct phy *phy_get(struct device *dev, const char *string);
struct phy *devm_phy_get(struct device *dev, const char *string);
struct phy *devm_phy_optional_get(struct device *dev,
const char *string);
struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
const char *con_id);
struct phy *devm_of_phy_optional_get(struct device *dev,
struct device_node *np,
const char *con_id);
struct phy *devm_of_phy_get_by_index(struct device *dev,
struct device_node *np,
int index);
phy_get, devm_phy_get and devm_phy_optional_get can be used to get the PHY.
In the case of dt boot, the string arguments
should contain the phy name as given in the dt data and in the case of
non-dt boot, it should contain the label of the PHY. The two
devm_phy_get associates the device with the PHY using devres on
successful PHY get. On driver detach, release function is invoked on
the devres data and devres data is freed.
The _optional_get variants should be used when the phy is optional. These
functions will never return -ENODEV, but instead return NULL when
the phy cannot be found.
Some generic drivers, such as ehci, may use multiple phys. In this case,
devm_of_phy_get or devm_of_phy_get_by_index can be used to get a phy
reference based on name or index.
It should be noted that NULL is a valid phy reference. All phy
consumer calls on the NULL phy become NOPs. That is the release calls,
the phy_init() and phy_exit() calls, and phy_power_on() and
phy_power_off() calls are all NOP when applied to a NULL phy. The NULL
phy is useful in devices for handling optional phy devices.
Order of API calls
==================
The general order of calls should be::
[devm_][of_]phy_get()
phy_init()
phy_power_on()
[phy_set_mode[_ext]()]
...
phy_power_off()
phy_exit()
[[of_]phy_put()]
Some PHY drivers may not implement :c:func:`phy_init` or :c:func:`phy_power_on`,
but controllers should always call these functions to be compatible with other
PHYs. Some PHYs may require :c:func:`phy_set_mode <phy_set_mode_ext>`, while
others may use a default mode (typically configured via devicetree or other
firmware). For compatibility, you should always call this function if you know
what mode you will be using. Generally, this function should be called after
:c:func:`phy_power_on`, although some PHY drivers may allow it at any time.
Releasing a reference to the PHY
================================
When the controller no longer needs the PHY, it has to release the reference
to the PHY it has obtained using the APIs mentioned in the above section. The
PHY framework provides 2 APIs to release a reference to the PHY.
::
void phy_put(struct phy *phy);
void devm_phy_put(struct device *dev, struct phy *phy);
Both these APIs are used to release a reference to the PHY and devm_phy_put
destroys the devres associated with this PHY.
Destroying the PHY
==================
When the driver that created the PHY is unloaded, it should destroy the PHY it
created using one of the following 2 APIs::
void phy_destroy(struct phy *phy);
void devm_phy_destroy(struct device *dev, struct phy *phy);
Both these APIs destroy the PHY and devm_phy_destroy destroys the devres
associated with this PHY.
PM Runtime
==========
This subsystem is pm runtime enabled. So while creating the PHY,
pm_runtime_enable of the phy device created by this subsystem is called and
while destroying the PHY, pm_runtime_disable is called. Note that the phy
device created by this subsystem will be a child of the device that calls
phy_create (PHY provider device).
So pm_runtime_get_sync of the phy_device created by this subsystem will invoke
pm_runtime_get_sync of PHY provider device because of parent-child relationship.
It should also be noted that phy_power_on and phy_power_off performs
phy_pm_runtime_get_sync and phy_pm_runtime_put respectively.
There are exported APIs like phy_pm_runtime_get, phy_pm_runtime_get_sync,
phy_pm_runtime_put and phy_pm_runtime_put_sync for performing PM operations.
PHY Mappings
============
In order to get reference to a PHY without help from DeviceTree, the framework
offers lookups which can be compared to clkdev that allow clk structures to be
bound to devices. A lookup can be made during runtime when a handle to the
struct phy already exists.
The framework offers the following API for registering and unregistering the
lookups::
int phy_create_lookup(struct phy *phy, const char *con_id,
const char *dev_id);
void phy_remove_lookup(struct phy *phy, const char *con_id,
const char *dev_id);
DeviceTree Binding
==================
The documentation for PHY dt binding can be found @
Documentation/devicetree/bindings/phy/phy-bindings.txt
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
PHY subsystem의 목적과 적용 범위
1-27Kishon Vijay Abraham I가 작성한 이 문서는 Generic PHY Framework가 제공하는 API와 사용 방법을 설명합니다. PHY는 physical layer의 약자로, device를 실제 전송 medium에 연결합니다.
예를 들어 USB controller의 PHY는 serialization, de-serialization, encoding, decoding을 수행하고 필요한 data transmission rate를 확보합니다. 어떤 USB controller는 PHY 기능을 내부에 포함하고, 다른 controller는 external PHY를 사용합니다. Wireless LAN, Ethernet, SATA도 PHY를 사용하는 대표적인 peripheral입니다.
이 framework의 목적은 커널 곳곳에 흩어진 PHY driver를 `drivers/phy`로 모아 code reuse와 유지보수성을 높이는 것입니다. Controller 안에 PHY 기능이 내장된 장치가 아니라 external PHY를 사용하는 장치에만 적용됩니다.
Generic PHY Framework는 controller와 physical medium 사이의 외부 PHY를 공통 API로 관리합니다.
=============
PHY subsystem
=============
:Author: Kishon Vijay Abraham I <[email protected]>
This document explains the Generic PHY Framework along with the APIs provided,
and how-to-use.
Introduction
============
*PHY* is the abbreviation for physical layer. It is used to connect a device
to the physical medium e.g., the USB controller has a PHY to provide functions
such as serialization, de-serialization, encoding, decoding and is responsible
for obtaining the required data transmission rate. Note that some USB
controllers have PHY functionality embedded into it and others use an external
PHY. Other peripherals that use PHY include Wireless LAN, Ethernet,
SATA etc.
The intention of creating this framework is to bring the PHY drivers spread
all over the Linux kernel to drivers/phy to increase code re-use and for
better code maintainability.
This framework will be of use only to devices that use external PHY (PHY
functionality is not embedded within the controller).
PHY provider 등록과 해제
28-73PHY provider는 하나 이상의 PHY instance를 구현하는 entity입니다. 단일 PHY provider에는 framework가 `of_phy_simple_xlate`라는 `of_xlate` 구현을 제공합니다. 여러 instance를 제공하면 provider가 자체 `of_xlate`를 구현해야 합니다. `of_xlate`는 DT boot에서만 사용됩니다.
`of_phy_provider_register(dev, xlate)`와 `devm_of_phy_provider_register(dev, xlate)` macro는 device와 `of_xlate`를 받아 각각 `__of_phy_provider_register()`와 `__devm_of_phy_provider_register()`를 호출합니다. DT boot의 모든 provider는 이 둘 중 하나로 등록해야 합니다.
Provider의 Device Tree node 아래에는 보통 PHY 하나를 나타내는 child node들이 있습니다. Binding이 context나 extensibility를 위해 child를 더 깊게 중첩한다면 `of_phy_provider_register_full()` 또는 `devm_of_phy_provider_register_full()`로 실제 child container node를 지정할 수 있습니다.
등록 해제에는 `of_phy_provider_unregister()`를 사용합니다. Managed provider는 `devm_of_phy_provider_unregister()`로 해제할 수 있으며 device 수명과 devres 정리를 맞춰야 합니다.
Registering/Unregistering the PHY provider
==========================================
PHY provider refers to an entity that implements one or more PHY instances.
For the simple case where the PHY provider implements only a single instance of
the PHY, the framework provides its own implementation of of_xlate in
of_phy_simple_xlate. If the PHY provider implements multiple instances, it
should provide its own implementation of of_xlate. of_xlate is used only for
dt boot case.
::
#define of_phy_provider_register(dev, xlate) \
__of_phy_provider_register((dev), NULL, THIS_MODULE, (xlate))
#define devm_of_phy_provider_register(dev, xlate) \
__devm_of_phy_provider_register((dev), NULL, THIS_MODULE,
(xlate))
of_phy_provider_register and devm_of_phy_provider_register macros can be used to
register the phy_provider and it takes device and of_xlate as
arguments. For the dt boot case, all PHY providers should use one of the above
2 macros to register the PHY provider.
Often the device tree nodes associated with a PHY provider will contain a set
of children that each represent a single PHY. Some bindings may nest the child
nodes within extra levels for context and extensibility, in which case the low
level of_phy_provider_register_full() and devm_of_phy_provider_register_full()
macros can be used to override the node containing the children.
::
#define of_phy_provider_register_full(dev, children, xlate) \
__of_phy_provider_register(dev, children, THIS_MODULE, xlate)
#define devm_of_phy_provider_register_full(dev, children, xlate) \
__devm_of_phy_provider_register_full(dev, children,
THIS_MODULE, xlate)
void devm_of_phy_provider_unregister(struct device *dev,
struct phy_provider *phy_provider);
void of_phy_provider_unregister(struct phy_provider *phy_provider);
devm_of_phy_provider_unregister and of_phy_provider_unregister can be used to
unregister the PHY.
PHY instance 생성과 private data
74-96다른 peripheral controller가 PHY를 사용하려면 PHY driver가 instance를 생성해야 합니다. 직접 관리 방식은 `phy_create(dev, node, ops)`, device-managed 방식은 `devm_phy_create(dev, node, ops)`입니다.
두 API 모두 provider device pointer, 해당 Device Tree node, `struct phy_ops`를 받습니다. `phy_ops`는 `init`, `exit`, `power_on`, `power_off` 같은 PHY operation을 수행하는 function pointer 집합입니다.
Provider의 private data는 PHY 생성 후 `phy_set_drvdata()`로 연결하고, `phy_ops` callback 안에서 `phy_get_drvdata()`로 다시 가져옵니다.
Provider state와 operation table을 PHY instance에 연결합니다.
Creating the PHY
================
The PHY driver should create the PHY in order for other peripheral controllers
to make use of it. The PHY framework provides 2 APIs to create the PHY.
::
struct phy *phy_create(struct device *dev, struct device_node *node,
const struct phy_ops *ops);
struct phy *devm_phy_create(struct device *dev,
struct device_node *node,
const struct phy_ops *ops);
The PHY drivers can use one of the above 2 APIs to create the PHY by passing
the device pointer and phy ops.
phy_ops is a set of function pointers for performing PHY operations such as
init, exit, power_on and power_off.
Inorder to dereference the private data (in phy_ops), the phy provider driver
can use phy_set_drvdata() after creating the PHY and use phy_get_drvdata() in
phy_ops to get back the private data.
Consumer의 PHY reference 획득과 optional PHY
97-137Controller는 PHY를 사용하기 전에 reference를 얻어야 합니다. 기본 API는 `phy_get()`, `devm_phy_get()`, `devm_phy_optional_get()`입니다. DT boot에서는 string 인자가 DT data에 기록된 PHY name이고, non-DT boot에서는 PHY label입니다.
Managed get은 성공한 PHY reference를 consumer device와 devres로 연결합니다. Driver detach 때 release callback이 호출되고 devres data가 해제됩니다.
Optional PHY에는 `_optional_get` 변형을 사용합니다. `devm_phy_optional_get()`과 `devm_of_phy_optional_get()`은 PHY를 찾지 못해도 `-ENODEV`를 반환하지 않고 `NULL`을 반환합니다.
EHCI 같은 generic driver가 여러 PHY를 사용할 때는 `devm_of_phy_get()`으로 name 기반 reference를 얻거나 `devm_of_phy_get_by_index()`로 index 기반 reference를 얻을 수 있습니다.
`NULL`은 유효한 PHY reference입니다. `NULL`에 대한 release, `phy_init()`, `phy_exit()`, `phy_power_on()`, `phy_power_off()` consumer call은 모두 NOP가 됩니다. 이 규칙 덕분에 optional PHY를 위해 각 호출을 별도 조건문으로 감쌀 필요가 없습니다.
Getting a reference to the PHY
==============================
Before the controller can make use of the PHY, it has to get a reference to
it. This framework provides the following APIs to get a reference to the PHY.
::
struct phy *phy_get(struct device *dev, const char *string);
struct phy *devm_phy_get(struct device *dev, const char *string);
struct phy *devm_phy_optional_get(struct device *dev,
const char *string);
struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
const char *con_id);
struct phy *devm_of_phy_optional_get(struct device *dev,
struct device_node *np,
const char *con_id);
struct phy *devm_of_phy_get_by_index(struct device *dev,
struct device_node *np,
int index);
phy_get, devm_phy_get and devm_phy_optional_get can be used to get the PHY.
In the case of dt boot, the string arguments
should contain the phy name as given in the dt data and in the case of
non-dt boot, it should contain the label of the PHY. The two
devm_phy_get associates the device with the PHY using devres on
successful PHY get. On driver detach, release function is invoked on
the devres data and devres data is freed.
The _optional_get variants should be used when the phy is optional. These
functions will never return -ENODEV, but instead return NULL when
the phy cannot be found.
Some generic drivers, such as ehci, may use multiple phys. In this case,
devm_of_phy_get or devm_of_phy_get_by_index can be used to get a phy
reference based on name or index.
It should be noted that NULL is a valid phy reference. All phy
consumer calls on the NULL phy become NOPs. That is the release calls,
the phy_init() and phy_exit() calls, and phy_power_on() and
phy_power_off() calls are all NOP when applied to a NULL phy. The NULL
phy is useful in devices for handling optional phy devices.
Consumer API 호출 순서
138-159일반 호출 순서는 `[devm_][of_]phy_get()`, `phy_init()`, `phy_power_on()`, 선택적인 `phy_set_mode[_ext]()`, 실제 사용, `phy_power_off()`, `phy_exit()`, 선택적인 `[[of_]phy_put()]`입니다.
일부 PHY driver가 `phy_init()` 또는 `phy_power_on()`을 구현하지 않더라도 controller는 다른 PHY와의 호환성을 위해 항상 호출해야 합니다.
어떤 PHY는 `phy_set_mode()` 또는 `phy_set_mode_ext()`가 필요하고, 다른 PHY는 Device Tree나 firmware의 default mode를 사용합니다. 사용할 mode를 알고 있다면 호환성을 위해 항상 설정해야 합니다. 일반적으로 `phy_power_on()` 뒤에 호출하지만, 일부 driver는 다른 시점도 허용합니다.
획득과 해제, init과 exit, power on과 off를 대칭으로 배치합니다.
Order of API calls
==================
The general order of calls should be::
[devm_][of_]phy_get()
phy_init()
phy_power_on()
[phy_set_mode[_ext]()]
...
phy_power_off()
phy_exit()
[[of_]phy_put()]
Some PHY drivers may not implement :c:func:`phy_init` or :c:func:`phy_power_on`,
but controllers should always call these functions to be compatible with other
PHYs. Some PHYs may require :c:func:`phy_set_mode <phy_set_mode_ext>`, while
others may use a default mode (typically configured via devicetree or other
firmware). For compatibility, you should always call this function if you know
what mode you will be using. Generally, this function should be called after
:c:func:`phy_power_on`, although some PHY drivers may allow it at any time.
Reference 해제와 PHY 파괴
160-186Controller가 PHY를 더 이상 사용하지 않으면 `phy_get()` 계열로 얻은 reference를 해제해야 합니다. `phy_put()`은 직접 reference를 반환하고, `devm_phy_put(dev, phy)`는 PHY와 연결된 devres도 파괴합니다.
PHY를 만든 provider driver가 unload될 때는 instance 자체를 파괴해야 합니다. 직접 생성한 PHY에는 `phy_destroy()`, managed PHY에는 `devm_phy_destroy()`를 사용합니다. 후자는 PHY를 파괴하면서 연결된 devres도 정리합니다.
Consumer reference 해제와 provider instance 파괴는 서로 다른 수명 단계입니다. 모든 consumer 사용이 끝난 뒤 provider의 등록·instance를 해제해야 합니다.
Releasing a reference to the PHY
================================
When the controller no longer needs the PHY, it has to release the reference
to the PHY it has obtained using the APIs mentioned in the above section. The
PHY framework provides 2 APIs to release a reference to the PHY.
::
void phy_put(struct phy *phy);
void devm_phy_put(struct device *dev, struct phy *phy);
Both these APIs are used to release a reference to the PHY and devm_phy_put
destroys the devres associated with this PHY.
Destroying the PHY
==================
When the driver that created the PHY is unloaded, it should destroy the PHY it
created using one of the following 2 APIs::
void phy_destroy(struct phy *phy);
void devm_phy_destroy(struct device *dev, struct phy *phy);
Both these APIs destroy the PHY and devm_phy_destroy destroys the devres
associated with this PHY.
PHY의 PM runtime 연동
187-202PHY subsystem은 PM runtime을 사용합니다. PHY를 생성할 때 subsystem이 만든 `phy_device`에 `pm_runtime_enable()`을 호출하고, PHY를 파괴할 때 `pm_runtime_disable()`을 호출합니다.
이 `phy_device`는 `phy_create()`를 호출한 PHY provider device의 child입니다. Parent-child 관계 때문에 `phy_device`의 `pm_runtime_get_sync()`는 provider device의 `pm_runtime_get_sync()`도 호출하게 됩니다.
`phy_power_on()`은 `phy_pm_runtime_get_sync()`를 수행하고 `phy_power_off()`는 `phy_pm_runtime_put()`을 수행합니다. 별도 PM operation에는 export된 `phy_pm_runtime_get()`, `phy_pm_runtime_get_sync()`, `phy_pm_runtime_put()`, `phy_pm_runtime_put_sync()`를 사용할 수 있습니다.
Child phy_device의 runtime PM 요청이 parent provider device로 전파됩니다.
PM Runtime
==========
This subsystem is pm runtime enabled. So while creating the PHY,
pm_runtime_enable of the phy device created by this subsystem is called and
while destroying the PHY, pm_runtime_disable is called. Note that the phy
device created by this subsystem will be a child of the device that calls
phy_create (PHY provider device).
So pm_runtime_get_sync of the phy_device created by this subsystem will invoke
pm_runtime_get_sync of PHY provider device because of parent-child relationship.
It should also be noted that phy_power_on and phy_power_off performs
phy_pm_runtime_get_sync and phy_pm_runtime_put respectively.
There are exported APIs like phy_pm_runtime_get, phy_pm_runtime_get_sync,
phy_pm_runtime_put and phy_pm_runtime_put_sync for performing PM operations.
Non-DT PHY mapping과 DeviceTree binding
203-223DeviceTree 도움 없이 PHY reference를 얻기 위해 framework는 `clkdev` lookup과 유사한 PHY mapping을 제공합니다. 이미 `struct phy` handle이 있는 runtime 시점에 device와 connection ID를 연결할 수 있습니다.
`phy_create_lookup(phy, con_id, dev_id)`는 lookup을 등록하고, `phy_remove_lookup(phy, con_id, dev_id)`는 같은 mapping을 해제합니다.
PHY DeviceTree binding 문서는 원문이 가리키는 `Documentation/devicetree/bindings/phy/phy-bindings.txt`에서 확인할 수 있습니다.
PHY Mappings
============
In order to get reference to a PHY without help from DeviceTree, the framework
offers lookups which can be compared to clkdev that allow clk structures to be
bound to devices. A lookup can be made during runtime when a handle to the
struct phy already exists.
The framework offers the following API for registering and unregistering the
lookups::
int phy_create_lookup(struct phy *phy, const char *con_id,
const char *dev_id);
void phy_remove_lookup(struct phy *phy, const char *con_id,
const char *dev_id);
DeviceTree Binding
==================
The documentation for PHY dt binding can be found @
Documentation/devicetree/bindings/phy/phy-bindings.txt
요약과 해설
phy.rst:1-223Generic PHY Framework는 external PHY provider와 consumer의 생성·reference·전원·파괴 수명을 공통화합니다. Managed API는 devres와 결합하고 optional get의 `NULL`은 유효한 NOP PHY이며, PM runtime 요청은 child PHY device에서 parent provider로 전파됩니다.