Re: [PATCH v18 6/8] phy: freescale: Add DisplayPort/HDMI Combo-PHY driver for i.MX8MQ

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 5 November 2024 14:05:51 GMT, Sandor Yu <sandor.yu@xxxxxxx> wrote:
>> 
>> On Tue, Oct 29, 2024 at 02:02:14PM +0800, Sandor Yu wrote:
>> > Add Cadence HDP-TX DisplayPort and HDMI PHY driver for i.MX8MQ.
>> >
>> > Cadence HDP-TX PHY could be put in either DP mode or
>> > HDMI mode base on the configuration chosen.
>> > DisplayPort or HDMI PHY mode is configured in the driver.
>> >
>> > Signed-off-by: Sandor Yu <Sandor.yu@xxxxxxx>
>> > Signed-off-by: Alexander Stein <alexander.stein@xxxxxxxxxxxxxxx>
>> > ---
>> > v17->v18:
>> > - fix build error as code rebase to latest kernel version.
>> >
>> >  drivers/phy/freescale/Kconfig                |   10 +
>> >  drivers/phy/freescale/Makefile               |    1 +
>> >  drivers/phy/freescale/phy-fsl-imx8mq-hdptx.c | 1337
>> ++++++++++++++++++
>> >  3 files changed, 1348 insertions(+)
>> >  create mode 100644 drivers/phy/freescale/phy-fsl-imx8mq-hdptx.c
>> >
>> > diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig
>> > index dcd9acff6d01a..2b1210367b31c 100644
>> > --- a/drivers/phy/freescale/Kconfig
>> > +++ b/drivers/phy/freescale/Kconfig
>> > @@ -35,6 +35,16 @@ config PHY_FSL_IMX8M_PCIE
>> >         Enable this to add support for the PCIE PHY as found on
>> >         i.MX8M family of SOCs.
>> >
>> > +config PHY_FSL_IMX8MQ_HDPTX
>> > +     tristate "Freescale i.MX8MQ DP/HDMI PHY support"
>> > +     depends on OF && HAS_IOMEM
>> > +     depends on COMMON_CLK
>> > +     select GENERIC_PHY
>> > +     select CDNS_MHDP_HELPER
>> 
>> This can have problems with being satisfied on randconfig builds,
>> because CDNS_MHDP_HELPER is deep inside the DRM tree.
>
>Yes, it should be. Change it to "depend on CDNS_MHDP_HELPER" will eliminate this problem.

No, depending on a non-user-selectable symbol is a bad idea. You should either depend/select all necessary symbols or, better in my opinion, move your helpers out of the DRM tree.


>
>> 
>> > +     help
>> > +       Enable this to support the Cadence HDPTX DP/HDMI PHY driver
>> > +       on i.MX8MQ SOC.
>> > +
>> >  config PHY_FSL_IMX8QM_HSIO
>> >       tristate "Freescale i.MX8QM HSIO PHY"
>> >       depends on OF && HAS_IOMEM
>> > diff --git a/drivers/phy/freescale/Makefile b/drivers/phy/freescale/Makefile
>> > index 658eac7d0a622..a946b87905498 100644
>> > --- a/drivers/phy/freescale/Makefile
>> > +++ b/drivers/phy/freescale/Makefile
>> > @@ -1,4 +1,5 @@
>> >  # SPDX-License-Identifier: GPL-2.0-only
>> > +obj-$(CONFIG_PHY_FSL_IMX8MQ_HDPTX)   += phy-fsl-imx8mq-hdptx.o
>> >  obj-$(CONFIG_PHY_FSL_IMX8MQ_USB)     += phy-fsl-imx8mq-usb.o
>> >  obj-$(CONFIG_PHY_MIXEL_LVDS_PHY)     +=
>> phy-fsl-imx8qm-lvds-phy.o
>> >  obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY)    += phy-fsl-imx8-mipi-dphy.o
>> > diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-hdptx.c
>> b/drivers/phy/freescale/phy-fsl-imx8mq-hdptx.c
>> > new file mode 100644
>> > index 0000000000000..7aac39df0ab02
>> > --- /dev/null
>> > +++ b/drivers/phy/freescale/phy-fsl-imx8mq-hdptx.c
>> > @@ -0,0 +1,1337 @@
>> > +// SPDX-License-Identifier: GPL-2.0-only
>> > +/*
>> > + * Cadence DP/HDMI PHY driver
>> > + *
>> > + * Copyright (C) 2022-2024 NXP Semiconductor, Inc.
>> > + */
>> > +#include <drm/bridge/cdns-mhdp-helper.h>
>> > +#include <linux/clk.h>
>> > +#include <linux/kernel.h>
>> > +#include <linux/phy/phy.h>
>> > +#include <linux/platform_device.h>
>> > +#include <linux/io.h>
>> > +#include <linux/unaligned.h>
>> > +
>> > +#define ADDR_PHY_AFE 0x80000
>> > +
>> > +/* PHY registers */
>> > +#define CMN_SSM_BIAS_TMR                     0x0022
>> > +#define CMN_PLLSM0_PLLEN_TMR                 0x0029
>> > +#define CMN_PLLSM0_PLLPRE_TMR                        0x002a
>> > +#define CMN_PLLSM0_PLLVREF_TMR                       0x002b
>> > +#define CMN_PLLSM0_PLLLOCK_TMR                       0x002c
>> > +#define CMN_PLLSM0_USER_DEF_CTRL             0x002f
>> > +#define CMN_PSM_CLK_CTRL                     0x0061
>> > +#define CMN_CDIAG_REFCLK_CTRL                        0x0062
>> > +#define CMN_PLL0_VCOCAL_START                        0x0081
>> > +#define CMN_PLL0_VCOCAL_INIT_TMR             0x0084
>> > +#define CMN_PLL0_VCOCAL_ITER_TMR             0x0085
>> > +#define CMN_PLL0_INTDIV                              0x0094
>> > +#define CMN_PLL0_FRACDIV                     0x0095
>> > +#define CMN_PLL0_HIGH_THR                    0x0096
>> > +#define CMN_PLL0_DSM_DIAG                    0x0097
>> > +#define CMN_PLL0_SS_CTRL2                    0x0099
>> > +#define CMN_ICAL_INIT_TMR                    0x00c4
>> > +#define CMN_ICAL_ITER_TMR                    0x00c5
>> > +#define CMN_RXCAL_INIT_TMR                   0x00d4
>> > +#define CMN_RXCAL_ITER_TMR                   0x00d5
>> > +#define CMN_TXPUCAL_CTRL                     0x00e0
>> > +#define CMN_TXPUCAL_INIT_TMR                 0x00e4
>> > +#define CMN_TXPUCAL_ITER_TMR                 0x00e5
>> > +#define CMN_TXPDCAL_CTRL                     0x00f0
>> > +#define CMN_TXPDCAL_INIT_TMR                 0x00f4
>> > +#define CMN_TXPDCAL_ITER_TMR                 0x00f5
>> > +#define CMN_ICAL_ADJ_INIT_TMR                        0x0102
>> > +#define CMN_ICAL_ADJ_ITER_TMR                        0x0103
>> > +#define CMN_RX_ADJ_INIT_TMR                  0x0106
>> > +#define CMN_RX_ADJ_ITER_TMR                  0x0107
>> > +#define CMN_TXPU_ADJ_CTRL                    0x0108
>> > +#define CMN_TXPU_ADJ_INIT_TMR                        0x010a
>> > +#define CMN_TXPU_ADJ_ITER_TMR                        0x010b
>> > +#define CMN_TXPD_ADJ_CTRL                    0x010c
>> > +#define CMN_TXPD_ADJ_INIT_TMR                        0x010e
>> > +#define CMN_TXPD_ADJ_ITER_TMR                        0x010f
>> > +#define CMN_DIAG_PLL0_FBH_OVRD                       0x01c0
>> > +#define CMN_DIAG_PLL0_FBL_OVRD                       0x01c1
>> > +#define CMN_DIAG_PLL0_OVRD                   0x01c2
>> > +#define CMN_DIAG_PLL0_TEST_MODE                      0x01c4
>> > +#define CMN_DIAG_PLL0_V2I_TUNE                       0x01c5
>> > +#define CMN_DIAG_PLL0_CP_TUNE                        0x01c6
>> > +#define CMN_DIAG_PLL0_LF_PROG                        0x01c7
>> > +#define CMN_DIAG_PLL0_PTATIS_TUNE1           0x01c8
>> > +#define CMN_DIAG_PLL0_PTATIS_TUNE2           0x01c9
>> > +#define CMN_DIAG_PLL0_INCLK_CTRL             0x01ca
>> > +#define CMN_DIAG_PLL0_PXL_DIVH                       0x01cb
>> > +#define CMN_DIAG_PLL0_PXL_DIVL                       0x01cc
>> > +#define CMN_DIAG_HSCLK_SEL                   0x01e0
>> > +#define CMN_DIAG_PER_CAL_ADJ                 0x01ec
>> > +#define CMN_DIAG_CAL_CTRL                    0x01ed
>> > +#define CMN_DIAG_ACYA                                0x01ff
>> > +#define XCVR_PSM_RCTRL                               0x4001
>> > +#define XCVR_PSM_CAL_TMR                     0x4002
>> > +#define XCVR_PSM_A0IN_TMR                    0x4003
>> > +#define TX_TXCC_CAL_SCLR_MULT_0                      0x4047
>> > +#define TX_TXCC_CPOST_MULT_00_0                      0x404c
>> > +#define XCVR_DIAG_PLLDRC_CTRL                        0x40e0
>> > +#define XCVR_DIAG_HSCLK_SEL                  0x40e1
>> > +#define XCVR_DIAG_BIDI_CTRL                  0x40e8
>> > +#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR
>> 0x40f2
>> > +#define TX_PSC_A0                            0x4100
>> > +#define TX_PSC_A1                            0x4101
>> > +#define TX_PSC_A2                            0x4102
>> > +#define TX_PSC_A3                            0x4103
>> > +#define TX_RCVDET_EN_TMR                     0x4122
>> > +#define TX_RCVDET_ST_TMR                     0x4123
>> > +#define TX_DIAG_TX_CTRL                              0x41e0
>> > +#define TX_DIAG_TX_DRV                               0x41e1
>> > +#define TX_DIAG_BGREF_PREDRV_DELAY           0x41e7
>> > +#define TX_DIAG_ACYA_0                               0x41ff
>> > +#define TX_DIAG_ACYA_1                               0x43ff
>> > +#define TX_DIAG_ACYA_2                               0x45ff
>> > +#define TX_DIAG_ACYA_3                               0x47ff
>> > +#define TX_ANA_CTRL_REG_1                    0x5020
>> > +#define TX_ANA_CTRL_REG_2                    0x5021
>> > +#define TX_DIG_CTRL_REG_1                    0x5023
>> > +#define TX_DIG_CTRL_REG_2                    0x5024
>> > +#define TXDA_CYA_AUXDA_CYA                   0x5025
>> > +#define TX_ANA_CTRL_REG_3                    0x5026
>> > +#define TX_ANA_CTRL_REG_4                    0x5027
>> > +#define TX_ANA_CTRL_REG_5                    0x5029
>> > +#define RX_PSC_A0                            0x8000
>> > +#define RX_PSC_CAL                           0x8006
>> > +#define PHY_HDP_MODE_CTRL                    0xc008
>> > +#define PHY_HDP_CLK_CTL                              0xc009
>> > +#define PHY_ISO_CMN_CTRL                     0xc010
>> > +#define PHY_PMA_CMN_CTRL1                    0xc800
>> > +#define PHY_PMA_ISO_CMN_CTRL                 0xc810
>> > +#define PHY_PMA_ISO_PLL_CTRL1                        0xc812
>> > +#define PHY_PMA_ISOLATION_CTRL                       0xc81f
>> > +
>> > +/* PHY_HDP_CLK_CTL */
>> > +#define PLL_DATA_RATE_CLK_DIV_MASK           GENMASK(15, 8)
>> > +#define PLL_DATA_RATE_CLK_DIV_HBR            0x24
>> > +#define PLL_DATA_RATE_CLK_DIV_HBR2           0x12
>> > +#define PLL_CLK_EN_ACK                               BIT(3)
>> > +#define PLL_CLK_EN                           BIT(2)
>> > +#define PLL_READY                            BIT(1)
>> > +#define PLL_EN                                       BIT(0)
>> > +
>> > +/* PHY_PMA_CMN_CTRL1 */
>> > +#define CMA_REF_CLK_DIG_DIV_MASK             GENMASK(13, 12)
>> > +#define CMA_REF_CLK_SEL_MASK                 GENMASK(6, 4)
>> > +#define CMA_REF_CLK_RCV_EN_MASK                      BIT(3)
>> > +#define CMA_REF_CLK_RCV_EN                   1
>> > +#define CMN_READY                            BIT(0)
>> > +
>> > +/* PHY_PMA_ISO_PLL_CTRL1 */
>> > +#define CMN_PLL0_CLK_DATART_DIV_MASK         GENMASK(7, 0)
>> > +
>> > +/* TX_DIAG_TX_DRV */
>> > +#define TX_DRIVER_PROG_BOOST_ENABLE          BIT(10)
>> > +#define TX_DRIVER_PROG_BOOST_LEVEL_MASK
>> GENMASK(9, 8)
>> > +#define TX_DRIVER_LDO_BG_DEPENDENT_REF_ENABLE        BIT(7)
>> > +#define TX_DRIVER_LDO_BANDGAP_REF_ENABLE     BIT(6)
>> > +
>> > +/* TX_TXCC_CAL_SCLR_MULT_0 */
>> > +#define SCALED_RESISTOR_CALIBRATION_CODE_ADD BIT(8)
>> > +#define RESISTOR_CAL_MULT_VAL_32_128         BIT(5)
>> > +
>> > +/* CMN_CDIAG_REFCLK_CTRL */
>> > +#define DIG_REF_CLK_DIV_SCALER_MASK          GENMASK(14, 12)
>> > +#define REFCLK_TERMINATION_EN_OVERRIDE_EN    BIT(7)
>> > +#define REFCLK_TERMINATION_EN_OVERRIDE               BIT(6)
>> > +
>> > +/* CMN_DIAG_HSCLK_SEL */
>> > +#define HSCLK1_SEL_MASK
>> GENMASK(5, 4)
>> > +#define HSCLK0_SEL_MASK
>> GENMASK(1, 0)
>> > +#define HSCLK_PLL0_DIV2                              1
>> > +
>> > +/* XCVR_DIAG_HSCLK_SEL */
>> > +#define HSCLK_SEL_MODE3_MASK                 GENMASK(13, 12)
>> > +#define HSCLK_SEL_MODE3_HSCLK1                       1
>> > +
>> > +/* CMN_PLL0_VCOCAL_START */
>> > +#define VCO_CALIB_CODE_START_POINT_VAL_MASK  GENMASK(8, 0)
>> > +
>> > +/* CMN_DIAG_PLL0_FBH_OVRD */
>> > +#define PLL_FEEDBACK_DIV_HI_OVERRIDE_EN              BIT(15)
>> > +
>> > +/* CMN_DIAG_PLL0_FBL_OVRD */
>> > +#define PLL_FEEDBACK_DIV_LO_OVERRIDE_EN              BIT(15)
>> > +
>> > +/* CMN_DIAG_PLL0_PXL_DIVH */
>> > +#define PLL_PCLK_DIV_EN                              BIT(15)
>> > +
>> > +/* XCVR_DIAG_PLLDRC_CTRL */
>> > +#define DPLL_CLK_SEL_MODE3                   BIT(14)
>> > +#define DPLL_DATA_RATE_DIV_MODE3_MASK
>> GENMASK(13, 12)
>> > +
>> > +/* TX_DIAG_TX_CTRL */
>> > +#define TX_IF_SUBRATE_MODE3_MASK             GENMASK(7, 6)
>> > +
>> > +/* PHY_HDP_MODE_CTRL */
>> > +#define POWER_STATE_A3_ACK                   BIT(7)
>> > +#define POWER_STATE_A2_ACK                   BIT(6)
>> > +#define POWER_STATE_A1_ACK                   BIT(5)
>> > +#define POWER_STATE_A0_ACK                   BIT(4)
>> > +#define POWER_STATE_A3                               BIT(3)
>> > +#define POWER_STATE_A2                               BIT(2)
>> > +#define POWER_STATE_A1                               BIT(1)
>> > +#define POWER_STATE_A0                               BIT(0)
>> > +
>> > +/* PHY_PMA_ISO_CMN_CTRL */
>> > +#define CMN_MACRO_PWR_EN_ACK                 BIT(5)
>> > +
>> > +#define KEEP_ALIVE           0x18
>> > +
>> > +#define REF_CLK_27MHZ                27000000
>> > +
>> > +/* HDMI TX clock control settings */
>> > +struct hdptx_hdmi_ctrl {
>> > +     u32 pixel_clk_freq_min;
>> > +     u32 pixel_clk_freq_max;
>> > +     u32 feedback_factor;
>> > +     u32 data_range_kbps_min;
>> > +     u32 data_range_kbps_max;
>> > +     u32 cmnda_pll0_ip_div;
>> > +     u32 cmn_ref_clk_dig_div;
>> > +     u32 ref_clk_divider_scaler;
>> > +     u32 pll_fb_div_total;
>> > +     u32 cmnda_pll0_fb_div_low;
>> > +     u32 cmnda_pll0_fb_div_high;
>> > +     u32 pixel_div_total;
>> > +     u32 cmnda_pll0_pxdiv_low;
>> > +     u32 cmnda_pll0_pxdiv_high;
>> > +     u32 vco_freq_min;
>> > +     u32 vco_freq_max;
>> > +     u32 vco_ring_select;
>> > +     u32 cmnda_hs_clk_0_sel;
>> > +     u32 cmnda_hs_clk_1_sel;
>> > +     u32 hsclk_div_at_xcvr;
>> > +     u32 hsclk_div_tx_sub_rate;
>> > +     u32 cmnda_pll0_hs_sym_div_sel;
>> > +     u32 cmnda_pll0_clk_freq_min;
>> > +     u32 cmnda_pll0_clk_freq_max;
>> > +};
>> > +
>> > +struct cdns_hdptx_phy {
>> > +     struct cdns_mhdp_base base;
>> > +
>> > +     void __iomem *regs;     /* DPTX registers base */
>> > +     struct device *dev;
>> > +     struct phy *phy;
>> > +     struct clk *ref_clk, *apb_clk;
>> > +     u32 ref_clk_rate;
>> > +     bool power_up;
>> > +     union {
>> > +             struct phy_configure_opts_hdmi hdmi;
>> > +             struct phy_configure_opts_dp dp;
>> > +     };
>> > +};
>> > +
>> > +/* HDMI TX clock control settings, pixel clock is output */
>> > +static const struct hdptx_hdmi_ctrl pixel_clk_output_ctrl_table[] = {
>> > +/*Minclk  Maxclk Fdbak  DR_min   DR_max  ip_d  dig  DS    Totl
>> */
>> > +{ 27000,  27000, 1000,  270000,  270000, 0x03, 0x1, 0x1,  240, 0x0bc,
>> 0x030,  80, 0x026, 0x026, 2160000, 2160000, 0, 2, 2, 2, 4, 0x3,  27000,
>> 27000},
>> > +{ 27000,  27000, 1250,  337500,  337500, 0x03, 0x1, 0x1,  300, 0x0ec,
>> 0x03c, 100, 0x030, 0x030, 2700000, 2700000, 0, 2, 2, 2, 4, 0x3,  33750,
>> 33750},
>> > +{ 27000,  27000, 1500,  405000,  405000, 0x03, 0x1, 0x1,  360, 0x11c,
>> 0x048, 120, 0x03a, 0x03a, 3240000, 3240000, 0, 2, 2, 2, 4, 0x3,  40500,
>> 40500},
>> > +{ 27000,  27000, 2000,  540000,  540000, 0x03, 0x1, 0x1,  240, 0x0bc,
>> 0x030,  80, 0x026, 0x026, 2160000, 2160000, 0, 2, 2, 2, 4, 0x2,  54000,
>> 54000},
>> > +{ 54000,  54000, 1000,  540000,  540000, 0x03, 0x1, 0x1,  480, 0x17c,
>> 0x060,  80, 0x026, 0x026, 4320000, 4320000, 1, 2, 2, 2, 4, 0x3,  54000,
>> 54000},
>> > +{ 54000,  54000, 1250,  675000,  675000, 0x04, 0x1, 0x1,  400, 0x13c,
>> 0x050,  50, 0x017, 0x017, 2700000, 2700000, 0, 1, 1, 2, 4, 0x2,  67500,
>> 67500},
>> > +{ 54000,  54000, 1500,  810000,  810000, 0x04, 0x1, 0x1,  480, 0x17c,
>> 0x060,  60, 0x01c, 0x01c, 3240000, 3240000, 0, 2, 2, 2, 2, 0x2,  81000,
>> 81000},
>> > +{ 54000,  54000, 2000, 1080000, 1080000, 0x03, 0x1, 0x1,  240, 0x0bc,
>> 0x030,  40, 0x012, 0x012, 2160000, 2160000, 0, 2, 2, 2, 1, 0x1, 108000,
>> 108000},
>> > +{ 74250,  74250, 1000,  742500,  742500, 0x03, 0x1, 0x1,  660, 0x20c,
>> 0x084,  80, 0x026, 0x026, 5940000, 5940000, 1, 2, 2, 2, 4, 0x3,  74250,
>> 74250},
>> > +{ 74250,  74250, 1250,  928125,  928125, 0x04, 0x1, 0x1,  550, 0x1b4,
>> 0x06e,  50, 0x017, 0x017, 3712500, 3712500, 1, 1, 1, 2, 4, 0x2,  92812,
>> 92812},
>> > +{ 74250,  74250, 1500, 1113750, 1113750, 0x04, 0x1, 0x1,  660, 0x20c,
>> 0x084,  60, 0x01c, 0x01c, 4455000, 4455000, 1, 2, 2, 2, 2, 0x2, 111375,
>> 111375},
>> > +{ 74250,  74250, 2000, 1485000, 1485000, 0x03, 0x1, 0x1,  330, 0x104,
>> 0x042,  40, 0x012, 0x012, 2970000, 2970000, 0, 2, 2, 2, 1, 0x1, 148500,
>> 148500},
>> > +{ 99000,  99000, 1000,  990000,  990000, 0x03, 0x1, 0x1,  440, 0x15c,
>> 0x058,  40, 0x012, 0x012, 3960000, 3960000, 1, 2, 2, 2, 2, 0x2,  99000,
>> 99000},
>> > +{ 99000,  99000, 1250, 1237500, 1237500, 0x03, 0x1, 0x1,  275, 0x0d8,
>> 0x037,  25, 0x00b, 0x00a, 2475000, 2475000, 0, 1, 1, 2, 2, 0x1, 123750,
>> 123750},
>> > +{ 99000,  99000, 1500, 1485000, 1485000, 0x03, 0x1, 0x1,  330, 0x104,
>> 0x042,  30, 0x00d, 0x00d, 2970000, 2970000, 0, 2, 2, 2, 1, 0x1, 148500,
>> 148500},
>> > +{ 99000,  99000, 2000, 1980000, 1980000, 0x03, 0x1, 0x1,  440, 0x15c,
>> 0x058,  40, 0x012, 0x012, 3960000, 3960000, 1, 2, 2, 2, 1, 0x1, 198000,
>> 198000},
>> > +{148500, 148500, 1000, 1485000, 1485000, 0x03, 0x1, 0x1,  660, 0x20c,
>> 0x084,  40, 0x012, 0x012, 5940000, 5940000, 1, 2, 2, 2, 2, 0x2, 148500,
>> 148500},
>> > +{148500, 148500, 1250, 1856250, 1856250, 0x04, 0x1, 0x1,  550, 0x1b4,
>> 0x06e,  25, 0x00b, 0x00a, 3712500, 3712500, 1, 1, 1, 2, 2, 0x1, 185625,
>> 185625},
>> > +{148500, 148500, 1500, 2227500, 2227500, 0x03, 0x1, 0x1,  495, 0x188,
>> 0x063,  30, 0x00d, 0x00d, 4455000, 4455000, 1, 1, 1, 2, 2, 0x1, 222750,
>> 222750},
>> > +{148500, 148500, 2000, 2970000, 2970000, 0x03, 0x1, 0x1,  660, 0x20c,
>> 0x084,  40, 0x012, 0x012, 5940000, 5940000, 1, 2, 2, 2, 1, 0x1, 297000,
>> 297000},
>> > +{198000, 198000, 1000, 1980000, 1980000, 0x03, 0x1, 0x1,  220, 0x0ac,
>> 0x02c,  10, 0x003, 0x003, 1980000, 1980000, 0, 1, 1, 2, 1, 0x0, 198000,
>> 198000},
>> > +{198000, 198000, 1250, 2475000, 2475000, 0x03, 0x1, 0x1,  550, 0x1b4,
>> 0x06e,  25, 0x00b, 0x00a, 4950000, 4950000, 1, 1, 1, 2, 2, 0x1, 247500,
>> 247500},
>> > +{198000, 198000, 1500, 2970000, 2970000, 0x03, 0x1, 0x1,  330, 0x104,
>> 0x042,  15, 0x006, 0x005, 2970000, 2970000, 0, 1, 1, 2, 1, 0x0, 297000,
>> 297000},
>> > +{198000, 198000, 2000, 3960000, 3960000, 0x03, 0x1, 0x1,  440, 0x15c,
>> 0x058,  20, 0x008, 0x008, 3960000, 3960000, 1, 1, 1, 2, 1, 0x0, 396000,
>> 396000},
>> > +{297000, 297000, 1000, 2970000, 2970000, 0x03, 0x1, 0x1,  330, 0x104,
>> 0x042,  10, 0x003, 0x003, 2970000, 2970000, 0, 1, 1, 2, 1, 0x0, 297000,
>> 297000},
>> > +{297000, 297000, 1500, 4455000, 4455000, 0x03, 0x1, 0x1,  495, 0x188,
>> 0x063,  15, 0x006, 0x005, 4455000, 4455000, 1, 1, 1, 2, 1, 0x0, 445500,
>> 445500},
>> > +{297000, 297000, 2000, 5940000, 5940000, 0x03, 0x1, 0x1,  660, 0x20c,
>> 0x084,  20, 0x008, 0x008, 5940000, 5940000, 1, 1, 1, 2, 1, 0x0, 594000,
>> 594000},
>> > +{594000, 594000, 1000, 5940000, 5940000, 0x03, 0x1, 0x1,  660, 0x20c,
>> 0x084,  10, 0x003, 0x003, 5940000, 5940000, 1, 1, 1, 2, 1, 0x0, 594000,
>> 594000},
>> > +{594000, 594000,  750, 4455000, 4455000, 0x03, 0x1, 0x1,  495, 0x188,
>> 0x063,  10, 0x003, 0x003, 4455000, 4455000, 1, 1, 1, 2, 1, 0x0, 445500,
>> 445500},
>> > +{594000, 594000,  625, 3712500, 3712500, 0x04, 0x1, 0x1,  550, 0x1b4,
>> 0x06e,  10, 0x003, 0x003, 3712500, 3712500, 1, 1, 1, 2, 1, 0x0, 371250,
>> 371250},
>> > +{594000, 594000,  500, 2970000, 2970000, 0x03, 0x1, 0x1,  660, 0x20c,
>> 0x084,  10, 0x003, 0x003, 5940000, 5940000, 1, 1, 1, 2, 2, 0x1, 297000,
>> 297000},
>> 
>> Is there a chance that this table or a part of it can be simplified or
>> calculated at runtime? For example, I think in all the cases minclk =
>> maxclk and DR_min = DR_max, dig and DS are always 0x1, etc.
>
>The calculation method used to generate this table is not publicly disclosed by the vendor.

I just pointed out how to simplify the table. If the exact method is not known, please apply some common sense to reduce duplication.

>
>This PHY operates in two modes: one where the pixel clock is generated internally by the PHY, 
>and another where the pixel clock is input externally. 
>The table above shows the configuration where the pixel clock is generated internally, 
>It is the PHY work mode for i.MX8MQ HDMI PHY. 
>When the pixel clock is input externally, the values for minclk, maxclk, DR_min, DR_max, dig, and DS are different. 
>This operating mode is used in other SOCs.

Make use of it when there is a need for that. You might have different tables or platform-specific code instead.


>
>> 
>> > +};
>> > +
>> > +/* HDMI TX PLL tuning settings */
>> > +struct hdptx_hdmi_pll_tuning {
>> > +     u32 vco_freq_bin;
>> > +     u32 vco_freq_min;
>> > +     u32 vco_freq_max;
>> > +     u32 volt_to_current_coarse;
>> > +     u32 volt_to_current;
>> > +     u32 ndac_ctrl;
>> > +     u32 pmos_ctrl;
>> > +     u32 ptat_ndac_ctrl;
>> > +     u32 feedback_div_total;
>> > +     u32 charge_pump_gain;
>> > +     u32 coarse_code;
>> > +     u32 v2i_code;
>> > +     u32 vco_cal_code;
>> > +};
>> > +
>> > +/* HDMI TX PLL tuning settings, pixel clock is output */
>> > +static const struct hdptx_hdmi_pll_tuning pixel_clk_output_pll_table[] = {
>> > +/*bin VCO_freq min/max  coar  cod NDAC  PMOS PTAT div-T P-Gain
>> Coa V2I CAL */
>> > +{  1, 1980000, 1980000, 0x4, 0x3, 0x0, 0x09, 0x09, 220, 0x42, 160, 5,
>> 183 },
>> > +{  2, 2160000, 2160000, 0x4, 0x3, 0x0, 0x09, 0x09, 240, 0x42, 166, 6,
>> 208 },
>> > +{  3, 2475000, 2475000, 0x5, 0x3, 0x1, 0x00, 0x07, 275, 0x42, 167, 6,
>> 209 },
>> > +{  4, 2700000, 2700000, 0x5, 0x3, 0x1, 0x00, 0x07, 300, 0x42, 188, 6,
>> 230 },
>> > +{  4, 2700000, 2700000, 0x5, 0x3, 0x1, 0x00, 0x07, 400, 0x4c, 188, 6,
>> 230 },
>> > +{  5, 2970000, 2970000, 0x6, 0x3, 0x1, 0x00, 0x07, 330, 0x42, 183, 6,
>> 225 },
>> > +{  6, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 360, 0x42, 203, 7,
>> 256 },
>> > +{  6, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 480, 0x4c, 203, 7,
>> 256 },
>> > +{  7, 3712500, 3712500, 0x4, 0x3, 0x0, 0x07, 0x0F, 550, 0x4c, 212, 7, 257 },
>> > +{  8, 3960000, 3960000, 0x5, 0x3, 0x0, 0x07, 0x0F, 440, 0x42, 184, 6, 226 },
>> > +{  9, 4320000, 4320000, 0x5, 0x3, 0x1, 0x07, 0x0F, 480, 0x42, 205, 7, 258 },
>> > +{ 10, 4455000, 4455000, 0x5, 0x3, 0x0, 0x07, 0x0F, 495, 0x42, 219, 7, 272 },
>> > +{ 10, 4455000, 4455000, 0x5, 0x3, 0x0, 0x07, 0x0F, 660, 0x4c, 219, 7, 272 },
>> > +{ 11, 4950000, 4950000, 0x6, 0x3, 0x1, 0x00, 0x07, 550, 0x42, 213, 7, 258 },
>> > +{ 12, 5940000, 5940000, 0x7, 0x3, 0x1, 0x00, 0x07, 660, 0x42, 244, 8, 292 },
>> > +};
>> > +
>> > +enum dp_link_rate {
>> > +     RATE_1_6 = 162000,
>> > +     RATE_2_1 = 216000,
>> > +     RATE_2_4 = 243000,
>> > +     RATE_2_7 = 270000,
>> > +     RATE_3_2 = 324000,
>> > +     RATE_4_3 = 432000,
>> > +     RATE_5_4 = 540000,
>> > +};
>> > +
>> > +#define MAX_LINK_RATE RATE_5_4
>> > +
>> > +struct phy_pll_reg {
>> > +     u16 val[7];
>> > +     u32 addr;
>> > +};
>> > +
>> > +static const struct phy_pll_reg phy_pll_27m_cfg[] = {
>> > +     /*  1.62    2.16    2.43    2.7     3.24    4.32    5.4
>> register address */
>> > +     {{ 0x010e, 0x010e, 0x010e, 0x010e, 0x010e, 0x010e, 0x010e },
>> CMN_PLL0_VCOCAL_INIT_TMR },
>> > +     {{ 0x001b, 0x001b, 0x001b, 0x001b, 0x001b, 0x001b, 0x001b },
>> CMN_PLL0_VCOCAL_ITER_TMR },
>> > +     {{ 0x30b9, 0x3087, 0x3096, 0x30b4, 0x30b9, 0x3087, 0x30b4 },
>> CMN_PLL0_VCOCAL_START },
>> > +     {{ 0x0077, 0x009f, 0x00b3, 0x00c7, 0x0077, 0x009f, 0x00c7 },
>> CMN_PLL0_INTDIV },
>> > +     {{ 0xf9da, 0xf7cd, 0xf6c7, 0xf5c1, 0xf9da, 0xf7cd, 0xf5c1 },
>> CMN_PLL0_FRACDIV },
>> > +     {{ 0x001e, 0x0028, 0x002d, 0x0032, 0x001e, 0x0028, 0x0032 },
>> CMN_PLL0_HIGH_THR },
>> > +     {{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 },
>> CMN_PLL0_DSM_DIAG },
>> > +     {{ 0x0000, 0x1000, 0x1000, 0x1000, 0x0000, 0x1000, 0x1000 },
>> CMN_PLLSM0_USER_DEF_CTRL },
>> > +     {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
>> CMN_DIAG_PLL0_OVRD },
>> > +     {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
>> CMN_DIAG_PLL0_FBH_OVRD },
>> > +     {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
>> CMN_DIAG_PLL0_FBL_OVRD },
>> > +     {{ 0x0006, 0x0007, 0x0007, 0x0007, 0x0006, 0x0007, 0x0007 },
>> CMN_DIAG_PLL0_V2I_TUNE },
>> > +     {{ 0x0043, 0x0043, 0x0043, 0x0042, 0x0043, 0x0043, 0x0042 },
>> CMN_DIAG_PLL0_CP_TUNE },
>> > +     {{ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008 },
>> CMN_DIAG_PLL0_LF_PROG },
>> > +     {{ 0x0100, 0x0001, 0x0001, 0x0001, 0x0100, 0x0001, 0x0001 },
>> CMN_DIAG_PLL0_PTATIS_TUNE1 },
>> > +     {{ 0x0007, 0x0001, 0x0001, 0x0001, 0x0007, 0x0001, 0x0001 },
>> CMN_DIAG_PLL0_PTATIS_TUNE2 },
>> > +     {{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 },
>> CMN_DIAG_PLL0_TEST_MODE},
>> > +     {{ 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016 },
>> CMN_PSM_CLK_CTRL }
>> > +};
>> > +
>> > +static int dp_link_rate_index(u32 rate)
>> > +{
>> > +     switch (rate) {
>> > +     case RATE_1_6:
>> > +             return 0;
>> > +     case RATE_2_1:
>> > +             return 1;
>> > +     case RATE_2_4:
>> > +             return 2;
>> > +     case RATE_2_7:
>> > +             return 3;
>> > +     case RATE_3_2:
>> > +             return 4;
>> > +     case RATE_4_3:
>> > +             return 5;
>> > +     case RATE_5_4:
>> 
>> If this is the only usage, please drop the enum.
>
>OK.
>
>> 
>> > +     default:
>> > +             return 6;
>> 
>> default should be -EINVAL
>> 
>
>OK.
>
>> 
>> > +     }
>> > +}
>> > +
>> > +static int cdns_phy_reg_write(struct cdns_hdptx_phy *cdns_phy, u32 addr,
>> u32 val)
>> > +{
>> > +     return cdns_mhdp_reg_write(&cdns_phy->base, ADDR_PHY_AFE +
>> (addr << 2), val);
>> > +}
>> > +
>> > +static u32 cdns_phy_reg_read(struct cdns_hdptx_phy *cdns_phy, u32
>> addr)
>> > +{
>> > +     u32 reg32;
>> > +
>> > +     cdns_mhdp_reg_read(&cdns_phy->base, ADDR_PHY_AFE + (addr <<
>> 2), &reg32);
>> > +
>> > +     return reg32;
>> > +}
>> > +
>> > +static void hdptx_dp_aux_cfg(struct cdns_hdptx_phy *cdns_phy)
>> > +{
>> > +     /* Power up Aux */
>> > +     cdns_phy_reg_write(cdns_phy, TXDA_CYA_AUXDA_CYA, 1);
>> > +
>> > +     cdns_phy_reg_write(cdns_phy, TX_DIG_CTRL_REG_1, 0x3);
>> > +     ndelay(150);
>> > +     cdns_phy_reg_write(cdns_phy, TX_DIG_CTRL_REG_2, 36);
>> > +     ndelay(150);
>> > +     cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x0100);
>> > +     ndelay(150);
>> > +     cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x0300);
>> > +     ndelay(150);
>> > +     cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_3, 0x0000);
>> > +     ndelay(150);
>> > +     cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0x2008);
>> > +     ndelay(150);
>> > +     cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0x2018);
>> > +     ndelay(150);
>> > +     cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0xa018);
>> > +     ndelay(150);
>> > +     cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x030c);
>> > +     ndelay(150);
>> > +     cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_5, 0x0000);
>> > +     ndelay(150);
>> > +     cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_4, 0x1001);
>> > +     ndelay(150);
>> > +     cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0xa098);
>> > +     ndelay(150);
>> > +     cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0xa198);
>> > +     ndelay(150);
>> > +     cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x030d);
>> > +     ndelay(150);
>> > +     cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x030f);
>> > +}
>> > +
>> > +/* PMA common configuration for 27MHz */
>> > +static void hdptx_dp_phy_pma_cmn_cfg_27mhz(struct cdns_hdptx_phy
>> *cdns_phy)
>> > +{
>> > +     u32 num_lanes = cdns_phy->dp.lanes;
>> > +     u16 val;
>> > +     int k;
>> > +
>> > +     /* Enable PMA input ref clk(CMN_REF_CLK_RCV_EN) */
>> > +     val = cdns_phy_reg_read(cdns_phy, PHY_PMA_CMN_CTRL1);
>> > +     val &= ~CMA_REF_CLK_RCV_EN_MASK;
>> > +     val |= FIELD_PREP(CMA_REF_CLK_RCV_EN_MASK,
>> CMA_REF_CLK_RCV_EN);
>> > +     cdns_phy_reg_write(cdns_phy, PHY_PMA_CMN_CTRL1, val);
>> > +
>> > +     /* Startup state machine registers */
>> > +     cdns_phy_reg_write(cdns_phy, CMN_SSM_BIAS_TMR, 0x0087);
>> > +     cdns_phy_reg_write(cdns_phy, CMN_PLLSM0_PLLEN_TMR,
>> 0x001b);
>> > +     cdns_phy_reg_write(cdns_phy, CMN_PLLSM0_PLLPRE_TMR,
>> 0x0036);
>> > +     cdns_phy_reg_write(cdns_phy, CMN_PLLSM0_PLLVREF_TMR,
>> 0x001b);
>> > +     cdns_phy_reg_write(cdns_phy, CMN_PLLSM0_PLLLOCK_TMR,
>> 0x006c);
>> > +
>> > +     /* Current calibration registers */
>> > +     cdns_phy_reg_write(cdns_phy, CMN_ICAL_INIT_TMR, 0x0044);
>> > +     cdns_phy_reg_write(cdns_phy, CMN_ICAL_ITER_TMR, 0x0006);
>> > +     cdns_phy_reg_write(cdns_phy, CMN_ICAL_ADJ_INIT_TMR,
>> 0x0022);
>> > +     cdns_phy_reg_write(cdns_phy, CMN_ICAL_ADJ_ITER_TMR,
>> 0x0006);
>> > +
>> > +     /* Resistor calibration registers */
>> > +     cdns_phy_reg_write(cdns_phy, CMN_TXPUCAL_INIT_TMR, 0x0022);
>> > +     cdns_phy_reg_write(cdns_phy, CMN_TXPUCAL_ITER_TMR,
>> 0x0006);
>> > +     cdns_phy_reg_write(cdns_phy, CMN_TXPU_ADJ_INIT_TMR,
>> 0x0022);
>> > +     cdns_phy_reg_write(cdns_phy, CMN_TXPU_ADJ_ITER_TMR,
>> 0x0006);
>> > +     cdns_phy_reg_write(cdns_phy, CMN_TXPDCAL_INIT_TMR, 0x0022);
>> > +     cdns_phy_reg_write(cdns_phy, CMN_TXPDCAL_ITER_TMR,
>> 0x0006);
>> > +     cdns_phy_reg_write(cdns_phy, CMN_TXPD_ADJ_INIT_TMR,
>> 0x0022);
>> > +     cdns_phy_reg_write(cdns_phy, CMN_TXPD_ADJ_ITER_TMR,
>> 0x0006);
>> > +     cdns_phy_reg_write(cdns_phy, CMN_RXCAL_INIT_TMR, 0x0022);
>> > +     cdns_phy_reg_write(cdns_phy, CMN_RXCAL_ITER_TMR, 0x0006);
>> > +     cdns_phy_reg_write(cdns_phy, CMN_RX_ADJ_INIT_TMR, 0x0022);
>> > +     cdns_phy_reg_write(cdns_phy, CMN_RX_ADJ_ITER_TMR, 0x0006);
>> > +
>> > +     for (k = 0; k < num_lanes; k = k + 1) {
>> > +             /* Power state machine registers */
>> > +             cdns_phy_reg_write(cdns_phy, XCVR_PSM_CAL_TMR  |
>> (k << 9), 0x016d);
>> > +             cdns_phy_reg_write(cdns_phy, XCVR_PSM_A0IN_TMR |
>> (k << 9), 0x016d);
>> > +             /* Transceiver control and diagnostic registers */
>> > +             cdns_phy_reg_write(cdns_phy,
>> XCVR_DIAG_LANE_FCM_EN_MGN_TMR | (k << 9), 0x00a2);
>> > +             cdns_phy_reg_write(cdns_phy,
>> TX_DIAG_BGREF_PREDRV_DELAY | (k << 9), 0x0097);
>> > +             /* Transmitter receiver detect registers */
>> > +             cdns_phy_reg_write(cdns_phy, TX_RCVDET_EN_TMR | (k
>> << 9), 0x0a8c);
>> > +             cdns_phy_reg_write(cdns_phy, TX_RCVDET_ST_TMR | (k
>> << 9), 0x0036);
>> > +     }
>> > +
>> > +     cdns_phy_reg_write(cdns_phy, TX_DIAG_ACYA_0, 1);
>> > +     cdns_phy_reg_write(cdns_phy, TX_DIAG_ACYA_1, 1);
>> > +     cdns_phy_reg_write(cdns_phy, TX_DIAG_ACYA_2, 1);
>> > +     cdns_phy_reg_write(cdns_phy, TX_DIAG_ACYA_3, 1);
>> > +}
>> > +
>> > +static void hdptx_dp_phy_pma_cmn_pll0_27mhz(struct cdns_hdptx_phy
>> *cdns_phy)
>> > +{
>> > +     u32 num_lanes = cdns_phy->dp.lanes;
>> > +     u32 link_rate = cdns_phy->dp.link_rate;
>> > +     u16 val;
>> > +     int index, i, k;
>> > +
>> > +     /* DP PLL data rate 0/1 clock divider value */
>> > +     val = cdns_phy_reg_read(cdns_phy, PHY_HDP_CLK_CTL);
>> > +     val &= ~PLL_DATA_RATE_CLK_DIV_MASK;
>> > +     if (link_rate <= RATE_2_7)
>> > +             val |= FIELD_PREP(PLL_DATA_RATE_CLK_DIV_MASK,
>> > +                               PLL_DATA_RATE_CLK_DIV_HBR);
>> > +     else
>> > +             val |= FIELD_PREP(PLL_DATA_RATE_CLK_DIV_MASK,
>> > +                               PLL_DATA_RATE_CLK_DIV_HBR2);
>> > +     cdns_phy_reg_write(cdns_phy, PHY_HDP_CLK_CTL, val);
>> > +
>> > +     /* High speed clock 0/1 div */
>> > +     val = cdns_phy_reg_read(cdns_phy, CMN_DIAG_HSCLK_SEL);
>> > +     val &= ~(HSCLK1_SEL_MASK | HSCLK0_SEL_MASK);
>> > +     if (link_rate <= RATE_2_7) {
>> > +             val |= FIELD_PREP(HSCLK1_SEL_MASK,
>> HSCLK_PLL0_DIV2);
>> > +             val |= FIELD_PREP(HSCLK0_SEL_MASK,
>> HSCLK_PLL0_DIV2);
>> > +     }
>> > +     cdns_phy_reg_write(cdns_phy, CMN_DIAG_HSCLK_SEL, val);
>> > +
>> > +     for (k = 0; k < num_lanes; k++) {
>> > +             val = cdns_phy_reg_read(cdns_phy,
>> (XCVR_DIAG_HSCLK_SEL | (k << 9)));
>> > +             val &= ~HSCLK_SEL_MODE3_MASK;
>> > +             if (link_rate <= RATE_2_7)
>> > +                     val |= FIELD_PREP(HSCLK_SEL_MODE3_MASK,
>> HSCLK_SEL_MODE3_HSCLK1);
>> > +             cdns_phy_reg_write(cdns_phy, (XCVR_DIAG_HSCLK_SEL |
>> (k << 9)), val);
>> > +     }
>> > +
>> > +     /* DP PHY PLL 27MHz configuration */
>> > +     index = dp_link_rate_index(link_rate);
>> > +     for (i = 0; i < ARRAY_SIZE(phy_pll_27m_cfg); i++)
>> > +             cdns_phy_reg_write(cdns_phy, phy_pll_27m_cfg[i].addr,
>> > +                                phy_pll_27m_cfg[i].val[index]);
>> > +
>> > +     /* Transceiver control and diagnostic registers */
>> > +     for (k = 0; k < num_lanes; k++) {
>> > +             val = cdns_phy_reg_read(cdns_phy,
>> (XCVR_DIAG_PLLDRC_CTRL | (k << 9)));
>> > +             val &= ~(DPLL_DATA_RATE_DIV_MODE3_MASK |
>> DPLL_CLK_SEL_MODE3);
>> > +             if (link_rate <= RATE_2_7)
>> > +                     val |=
>> FIELD_PREP(DPLL_DATA_RATE_DIV_MODE3_MASK, 2);
>> > +             else
>> > +                     val |=
>> FIELD_PREP(DPLL_DATA_RATE_DIV_MODE3_MASK, 1);
>> > +             cdns_phy_reg_write(cdns_phy,
>> (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val);
>> > +     }
>> > +
>> > +     for (k = 0; k < num_lanes; k = k + 1) {
>> > +





[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux