mbox series

[0/8] soc: samsung: Add USIv2 driver

Message ID 20211127223253.19098-1-semen.protsenko@linaro.org
Headers show
Series soc: samsung: Add USIv2 driver | expand

Message

Sam Protsenko Nov. 27, 2021, 10:32 p.m. UTC
USIv2 IP-core provides selectable serial protocol (UART, SPI or
High-Speed I2C); only one can be chosen at a time. This series
implements USIv2 driver, which allows one to select particular USI
function in device tree, and also performs USI block initialization.

With that driver implemented, it's not needed to do USI initialization
in protocol drivers anymore, so that code is removed from the serial
driver.

Because USI driver is tristate (can be built as a module), serial driver
was reworked so it's possible to use its console part as a module too.
This way we can load serial driver module from user space and still have
serial console functional.

Make it impossible to build UART/SPI/I2C driver as a built-in when USIv2
driver built as a module: USIv2 configuration must be always done before
tinkering with particular protocol it implements.

Design features:
  - "reg" property contains USI registers start address (0xc0 offset);
    it's used in the driver to access USI_CON and USI_OPTION registers.
    This way all USI initialization (reset, HWACG, etc) can be done in
    USIv2 driver separately, rather than duplicating that code over
    UART/SPI/I2C drivers
  - System Register (system controller node) and its SW_CONF register
    offset are provided in "samsung,sysreg" property; it's used to
    select USI function (protocol to be used)
  - USI function is specified in "samsung,mode" property; integer value
    is used to simplify parsing
  - there is "samsung,clkreq-on" bool property, which makes driver
    disable HWACG control (needed for UART to work properly)
  - PCLK and IPCLK clocks are both provided to USI node; apparently both
    need to be enabled to access USI registers
  - protocol nodes are embedded (as a child nodes) in USI node; it
    allows correct init order, and reflects HW properly
  - USIv2 driver is a tristate: can be also useful from Android GKI
    requirements point of view
  - driver functions are implemented with further development in mind:
    we might want to add some SysFS interface later for example, or
    provide some functions to serial drivers with EXPORT_SYMBOL(), etc

Sam Protsenko (8):
  dt-bindings: soc: samsung: Add Exynos USIv2 bindings
  dt-bindings: soc: samsung: Add Exynos USIv2 bindings doc
  soc: samsung: Add USIv2 driver
  tty: serial: samsung: Remove USI initialization
  tty: serial: samsung: Enable console as module
  tty: serial: Make SERIAL_SAMSUNG=y impossible when EXYNOS_USI_V2=m
  i2c: Make I2C_EXYNOS5=y impossible when EXYNOS_USI_V2=m
  spi: Make SPI_S3C64XX=y impossible when EXYNOS_USI_V2=m

 .../bindings/soc/samsung/exynos-usi-v2.yaml   | 124 +++++++++
 drivers/i2c/busses/Kconfig                    |   1 +
 drivers/soc/samsung/Kconfig                   |  14 +
 drivers/soc/samsung/Makefile                  |   2 +
 drivers/soc/samsung/exynos-usi-v2.c           | 242 ++++++++++++++++++
 drivers/spi/Kconfig                           |   1 +
 drivers/tty/serial/Kconfig                    |   3 +-
 drivers/tty/serial/samsung_tty.c              |  57 ++---
 .../dt-bindings/soc/samsung,exynos-usi-v2.h   |  16 ++
 include/linux/serial_s3c.h                    |   9 -
 10 files changed, 425 insertions(+), 44 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/soc/samsung/exynos-usi-v2.yaml
 create mode 100644 drivers/soc/samsung/exynos-usi-v2.c
 create mode 100644 include/dt-bindings/soc/samsung,exynos-usi-v2.h

Comments

David Virag Nov. 28, 2021, 3:15 a.m. UTC | #1
On Sun, 2021-11-28 at 00:32 +0200, Sam Protsenko wrote:
> USIv2 IP-core provides selectable serial protocol (UART, SPI or
> High-Speed I2C); only one can be chosen at a time. This series
> implements USIv2 driver, which allows one to select particular USI
> function in device tree, and also performs USI block initialization.
> 
> With that driver implemented, it's not needed to do USI
> initialization
> in protocol drivers anymore, so that code is removed from the serial
> driver.
> 

I think the downstream way of doing this (USI node reg being on the
SW_CONF register itself rather than an offset from uart/i2c/spi, the
USI driver only controlling the SW_CONF, and the uart/i2c/spi drivers
controlling their USI_CON and USI_OPTION regs) is cleaner, better, and
easier to adapt to USIv1 too.

For example: I'm sure this is the case on USIv2 devices too, but on
Exynos7885, different devices have USI modes configured differently.
For example a Samsung Galaxy A8 (2018) has all the USI blocks
configured as SPI while a Samsung Galaxy M20 has the first USI
configured as dual HSI2C, the second as HSI2C on the first 2 pins and
the third as HSI2C on the last 2 pins. With this way of doing
everything on USIv2 we'd need 3 disabled USIv2 nodes in the SoC DTSI
for one USI block, each for every protocol the USI block can do, all
having a single child for their protocol and each referencing the same
sysreg (not even sure if that's even supported). Then the board DTS
could enable the USI node it needs.

With the downstream way we could have just one USI node and we could
add the 3 protocols it can do disabled as seperate or child nodes. This
way the board DTS only needs to set the appropriate mode setting and
enable the protocol it needs. I'd say much better than having 3 USI
nodes for the same USI block.

Also this way is pretty USIv2 centric. Adding USIv1 support to this
driver is difficult this way because of the the lack of USI_CON and
USI_OPTION registers as a whole (so having nowhere to actually set the
reg of the USI node to, as the only thing USIv1 has is the SW_CONF
register). In my opinion being able to use the same driver and same
device tree layout for USIv1 and USIv2 is a definite plus

The only real drawback of that way is having to add code for USIv2
inside the UART, HSI2C, and SPI drivers but in my opinion the benefits
overweigh the drawbacks greatly. We could even make the uart/spi/hsi2c
drivers call a helper function in the USI driver to set their USI_CON
and USI_OPTION registers up so that code would be shared and not
duplicated. Wether this patch gets applied like this is not my choice
though, I'll let the people responsible decide
:-)

Anyways, soon enough I can write an USIv1 driver after I submit all the
7885 stuff I'm working on currently. If you want to, you can add USIv2
support to that driver, or if an USIv2 driver is already in upstream at
that point, if it is written in the downstream way I can add v1 support
to that, or if it's like this I'll have to make a whole seperate driver
with a whole seperate DT structure.

Best regards,
David
Krzysztof Kozlowski Nov. 29, 2021, 9:02 a.m. UTC | #2
On 28/11/2021 04:15, David Virag wrote:
> On Sun, 2021-11-28 at 00:32 +0200, Sam Protsenko wrote:
>> USIv2 IP-core provides selectable serial protocol (UART, SPI or
>> High-Speed I2C); only one can be chosen at a time. This series
>> implements USIv2 driver, which allows one to select particular USI
>> function in device tree, and also performs USI block initialization.
>>
>> With that driver implemented, it's not needed to do USI
>> initialization
>> in protocol drivers anymore, so that code is removed from the serial
>> driver.
>>
> 
> I think the downstream way of doing this (USI node reg being on the
> SW_CONF register itself rather than an offset from uart/i2c/spi, the
> USI driver only controlling the SW_CONF, and the uart/i2c/spi drivers
> controlling their USI_CON and USI_OPTION regs) is cleaner, better, and
> easier to adapt to USIv1 too.
> 
> For example: I'm sure this is the case on USIv2 devices too, but on
> Exynos7885, different devices have USI modes configured differently.
> For example a Samsung Galaxy A8 (2018) has all the USI blocks
> configured as SPI while a Samsung Galaxy M20 has the first USI
> configured as dual HSI2C, the second as HSI2C on the first 2 pins and
> the third as HSI2C on the last 2 pins. With this way of doing
> everything on USIv2 we'd need 3 disabled USIv2 nodes in the SoC DTSI
> for one USI block, each for every protocol the USI block can do, all
> having a single child for their protocol and each referencing the same
> sysreg (not even sure if that's even supported). Then the board DTS
> could enable the USI node it needs.

It's not supported (one cannot have three same nodes with same unit
addresses), so this would be solved by dropping out unused interfaces,
commenting them out or storing everything under one USI:

usi@0x1abcdef0 {
  serial@.... {
    status = "okay";
  }

  i2c@.... {
    status = "disabled";
  }

  spi@.... {
    status = "disabled";
  }
}

> 
> With the downstream way we could have just one USI node and we could
> add the 3 protocols it can do disabled as seperate or child nodes. This
> way the board DTS only needs to set the appropriate mode setting and
> enable the protocol it needs. I'd say much better than having 3 USI
> nodes for the same USI block.

Then however you need to handle probe ordering and possible probe deferrals.

> 
> Also this way is pretty USIv2 centric. Adding USIv1 support to this
> driver is difficult this way because of the the lack of USI_CON and
> USI_OPTION registers as a whole (so having nowhere to actually set the
> reg of the USI node to, as the only thing USIv1 has is the SW_CONF
> register). 

How is it difficult? Not having a register is easy - noop on given platform.

> In my opinion being able to use the same driver and same
> device tree layout for USIv1 and USIv2 is a definite plus
> 
> The only real drawback of that way is having to add code for USIv2
> inside the UART, HSI2C, and SPI drivers but in my opinion the benefits
> overweigh the drawbacks greatly. We could even make the uart/spi/hsi2c
> drivers call a helper function in the USI driver to set their USI_CON
> and USI_OPTION registers up so that code would be shared and not
> duplicated. Wether this patch gets applied like this is not my choice
> though, I'll let the people responsible decide
> :-)
> 
> Anyways, soon enough I can write an USIv1 driver after I submit all the
> 7885 stuff I'm working on currently. If you want to, you can add USIv2
> support to that driver, or if an USIv2 driver is already in upstream at
> that point, if it is written in the downstream way I can add v1 support
> to that, or if it's like this I'll have to make a whole seperate driver
> with a whole seperate DT structure.
> 
> Best regards,
> David
> 


Best regards,
Krzysztof