diff mbox series

[v6,4/5] drm/bridge: anx7625: add HDCP support

Message ID 189a637c87827f78c433a053e3c2129ebec73188.1616135353.git.xji@analogixsemi.com (mailing list archive)
State New, archived
Headers show
Series Add MIPI rx DPI support | expand

Commit Message

Xin Ji March 19, 2021, 6:34 a.m. UTC
Add HDCP feature, enable HDCP function through chip internal key
and downstream's capability.

Signed-off-by: Xin Ji <xji@analogixsemi.com>
---
 drivers/gpu/drm/bridge/analogix/anx7625.c | 147 ++++++++++++++++++++++
 drivers/gpu/drm/bridge/analogix/anx7625.h |  36 ++++++
 2 files changed, 183 insertions(+)

Comments

Sean Paul March 25, 2021, 6:19 p.m. UTC | #1
On Fri, Mar 19, 2021 at 2:35 AM Xin Ji <xji@analogixsemi.com> wrote:
>
> Add HDCP feature, enable HDCP function through chip internal key
> and downstream's capability.
>
> Signed-off-by: Xin Ji <xji@analogixsemi.com>
> ---
>  drivers/gpu/drm/bridge/analogix/anx7625.c | 147 ++++++++++++++++++++++
>  drivers/gpu/drm/bridge/analogix/anx7625.h |  36 ++++++
>  2 files changed, 183 insertions(+)
>
> diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c
> index 8c514b46d361..b424a570effa 100644
> --- a/drivers/gpu/drm/bridge/analogix/anx7625.c
> +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
> @@ -633,6 +633,150 @@ static int anx7625_dpi_config(struct anx7625_data *ctx)
>         return ret;
>  }
>
> +static int anx7625_aux_dpcd_read(struct anx7625_data *ctx,
> +                                u8 addrh, u8 addrm, u8 addrl,
> +                                u8 len, u8 *buf)
> +{
> +       struct device *dev = &ctx->client->dev;
> +       int ret;
> +       u8 cmd;
> +
> +       if (len > MAX_DPCD_BUFFER_SIZE) {
> +               DRM_DEV_ERROR(dev, "exceed aux buffer len.\n");
> +               return -E2BIG;
> +       }
> +
> +       cmd = ((len - 1) << 4) | 0x09;
> +
> +       /* Set command and length */
> +       ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> +                               AP_AUX_COMMAND, cmd);
> +
> +       /* Set aux access address */
> +       ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> +                                AP_AUX_ADDR_7_0, addrl);
> +       ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> +                                AP_AUX_ADDR_15_8, addrm);
> +       ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> +                                AP_AUX_ADDR_19_16, addrh);
> +
> +       /* Enable aux access */
> +       ret |= anx7625_write_or(ctx, ctx->i2c.rx_p0_client,
> +                               AP_AUX_CTRL_STATUS, AP_AUX_CTRL_OP_EN);
> +
> +       if (ret < 0) {
> +               DRM_DEV_ERROR(dev, "cannot access aux related register.\n");
> +               return -EIO;
> +       }
> +
> +       usleep_range(2000, 2100);
> +
> +       ret = wait_aux_op_finish(ctx);
> +       if (ret) {
> +               DRM_DEV_ERROR(dev, "aux IO error: wait aux op finish.\n");
> +               return ret;
> +       }
> +
> +       ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client,
> +                                    AP_AUX_BUFF_START, len, buf);
> +       if (ret < 0) {
> +               DRM_DEV_ERROR(dev, "read dpcd register failed\n");
> +               return -EIO;
> +       }
> +
> +       return 0;
> +}
> +
> +static int anx7625_read_flash_status(struct anx7625_data *ctx)
> +{
> +       return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, R_RAM_CTRL);
> +}
> +
> +static int anx7625_hdcp_key_probe(struct anx7625_data *ctx)
> +{
> +       int ret, val;
> +       struct device *dev = &ctx->client->dev;
> +       u8 ident[32];
> +
> +       ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> +                               FLASH_ADDR_HIGH, 0x91);
> +       ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> +                                FLASH_ADDR_LOW, 0xA0);
> +       if (ret < 0) {
> +               DRM_DEV_ERROR(dev, "IO error : set key flash address.\n");
> +               return ret;
> +       }
> +
> +       ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> +                               FLASH_LEN_HIGH, (FLASH_BUF_LEN - 1) >> 8);
> +       ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> +                                FLASH_LEN_LOW, (FLASH_BUF_LEN - 1) & 0xFF);
> +       if (ret < 0) {
> +               DRM_DEV_ERROR(dev, "IO error : set key flash len.\n");
> +               return ret;
> +       }
> +
> +       ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> +                               R_FLASH_RW_CTRL, FLASH_READ);
> +       ret |= readx_poll_timeout(anx7625_read_flash_status,
> +                                 ctx, val,
> +                                 ((val & FLASH_DONE) || (val < 0)),
> +                                 2000,
> +                                 2000 * 150);
> +       if (ret) {
> +               DRM_DEV_ERROR(dev, "flash read access fail!\n");
> +               return -EIO;
> +       }
> +
> +       ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client,
> +                                    FLASH_BUF_BASE_ADDR,
> +                                    FLASH_BUF_LEN, ident);
> +       if (ret < 0) {
> +               DRM_DEV_ERROR(dev, "read flash data fail!\n");
> +               return -EIO;
> +       }
> +
> +       if (ident[29] == 0xFF && ident[30] == 0xFF && ident[31] == 0xFF)
> +               return -EINVAL;
> +
> +       return 0;
> +}
> +
> +static int anx7625_hdcp_setting(struct anx7625_data *ctx)
> +{
> +       u8 bcap;
> +       int ret;
> +       struct device *dev = &ctx->client->dev;
> +
> +       ret = anx7625_hdcp_key_probe(ctx);
> +       if (ret) {
> +               DRM_DEV_DEBUG_DRIVER(dev, "disable HDCP by config\n");
> +               return anx7625_write_and(ctx, ctx->i2c.rx_p1_client,
> +                                        0xee, 0x9f);
> +       }
> +
> +       anx7625_aux_dpcd_read(ctx, 0x06, 0x80, 0x28, 1, &bcap);
> +       if (!(bcap & 0x01)) {
> +               DRM_DEV_DEBUG_DRIVER(dev, "bcap(0x%x) not support HDCP 1.4.\n",
> +                                    bcap);
> +               return anx7625_write_and(ctx, ctx->i2c.rx_p1_client,
> +                                        0xee, 0x9f);
> +       }
> +
> +       DRM_DEV_DEBUG_DRIVER(dev, "enable HDCP 1.4\n");
> +
> +       ret = anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xee, 0x20);
> +
> +       /* Try auth flag */
> +       ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xec, 0x10);
> +       /* Interrupt for DRM */
> +       ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xff, 0x01);
> +       if (ret < 0)
> +               DRM_DEV_ERROR(dev, "fail to enable HDCP\n");
> +
> +       return ret;
> +}
> +
>  static void anx7625_dp_start(struct anx7625_data *ctx)
>  {
>         int ret;
> @@ -643,6 +787,9 @@ static void anx7625_dp_start(struct anx7625_data *ctx)
>                 return;
>         }
>
> +       /* HDCP config */
> +       anx7625_hdcp_setting(ctx);

You should really use the "Content Protection" property to
enable/disable HDCP instead of force-enabling it at all times.

Sean

> +
>         if (ctx->pdata.is_dpi)
>                 ret = anx7625_dpi_config(ctx);
>         else
> diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h
> index beee95da2155..c6f93e4df0ed 100644
> --- a/drivers/gpu/drm/bridge/analogix/anx7625.h
> +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h
> @@ -154,9 +154,45 @@
>
>  #define  I2C_ADDR_7E_FLASH_CONTROLLER  0x7E
>
> +#define FLASH_SRAM_SEL          0x00
> +#define SRAM_ADDR_HIGH          0x01
> +#define SRAM_ADDR_LOW           0x02
> +#define SRAM_LEN_HIGH           0x03
> +#define SRAM_LEN_LOW            0x04
>  #define FLASH_LOAD_STA          0x05
>  #define FLASH_LOAD_STA_CHK     BIT(7)
>
> +#define R_RAM_CTRL              0x05
> +/* bit positions */
> +#define FLASH_DONE              BIT(7)
> +#define BOOT_LOAD_DONE          BIT(6)
> +#define CRC_OK                  BIT(5)
> +#define LOAD_DONE               BIT(4)
> +#define O_RW_DONE               BIT(3)
> +#define FUSE_BUSY               BIT(2)
> +#define DECRYPT_EN              BIT(1)
> +#define LOAD_START              BIT(0)
> +
> +#define FLASH_ADDR_HIGH         0x0F
> +#define FLASH_ADDR_LOW          0x10
> +#define FLASH_LEN_HIGH          0x31
> +#define FLASH_LEN_LOW           0x32
> +
> +#define R_FLASH_RW_CTRL         0x33
> +/* bit positions */
> +#define READ_DELAY_SELECT       BIT(7)
> +#define GENERAL_INSTRUCTION_EN  BIT(6)
> +#define FLASH_ERASE_EN          BIT(5)
> +#define RDID_READ_EN            BIT(4)
> +#define REMS_READ_EN            BIT(3)
> +#define WRITE_STATUS_EN         BIT(2)
> +#define FLASH_READ              BIT(1)
> +#define FLASH_WRITE             BIT(0)
> +
> +#define FLASH_BUF_BASE_ADDR     0x60
> +#define FLASH_BUF_LEN           0x20
> +#define FLASH_KEY_OFFSET        0x8000
> +
>  #define  XTAL_FRQ_SEL    0x3F
>  /* bit field positions */
>  #define  XTAL_FRQ_SEL_POS    5
> --
> 2.25.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
Xin Ji March 29, 2021, 10:27 a.m. UTC | #2
On Thu, Mar 25, 2021 at 02:19:23PM -0400, Sean Paul wrote:
> On Fri, Mar 19, 2021 at 2:35 AM Xin Ji <xji@analogixsemi.com> wrote:
> >
> > Add HDCP feature, enable HDCP function through chip internal key
> > and downstream's capability.
> >
> > Signed-off-by: Xin Ji <xji@analogixsemi.com>
> > ---
> >  drivers/gpu/drm/bridge/analogix/anx7625.c | 147 ++++++++++++++++++++++
> >  drivers/gpu/drm/bridge/analogix/anx7625.h |  36 ++++++
> >  2 files changed, 183 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c
> > index 8c514b46d361..b424a570effa 100644
> > --- a/drivers/gpu/drm/bridge/analogix/anx7625.c
> > +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
> > @@ -633,6 +633,150 @@ static int anx7625_dpi_config(struct anx7625_data *ctx)
> >         return ret;
> >  }
> >
> > +static int anx7625_aux_dpcd_read(struct anx7625_data *ctx,
> > +                                u8 addrh, u8 addrm, u8 addrl,
> > +                                u8 len, u8 *buf)
> > +{
> > +       struct device *dev = &ctx->client->dev;
> > +       int ret;
> > +       u8 cmd;
> > +
> > +       if (len > MAX_DPCD_BUFFER_SIZE) {
> > +               DRM_DEV_ERROR(dev, "exceed aux buffer len.\n");
> > +               return -E2BIG;
> > +       }
> > +
> > +       cmd = ((len - 1) << 4) | 0x09;
> > +
> > +       /* Set command and length */
> > +       ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +                               AP_AUX_COMMAND, cmd);
> > +
> > +       /* Set aux access address */
> > +       ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +                                AP_AUX_ADDR_7_0, addrl);
> > +       ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +                                AP_AUX_ADDR_15_8, addrm);
> > +       ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +                                AP_AUX_ADDR_19_16, addrh);
> > +
> > +       /* Enable aux access */
> > +       ret |= anx7625_write_or(ctx, ctx->i2c.rx_p0_client,
> > +                               AP_AUX_CTRL_STATUS, AP_AUX_CTRL_OP_EN);
> > +
> > +       if (ret < 0) {
> > +               DRM_DEV_ERROR(dev, "cannot access aux related register.\n");
> > +               return -EIO;
> > +       }
> > +
> > +       usleep_range(2000, 2100);
> > +
> > +       ret = wait_aux_op_finish(ctx);
> > +       if (ret) {
> > +               DRM_DEV_ERROR(dev, "aux IO error: wait aux op finish.\n");
> > +               return ret;
> > +       }
> > +
> > +       ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client,
> > +                                    AP_AUX_BUFF_START, len, buf);
> > +       if (ret < 0) {
> > +               DRM_DEV_ERROR(dev, "read dpcd register failed\n");
> > +               return -EIO;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static int anx7625_read_flash_status(struct anx7625_data *ctx)
> > +{
> > +       return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, R_RAM_CTRL);
> > +}
> > +
> > +static int anx7625_hdcp_key_probe(struct anx7625_data *ctx)
> > +{
> > +       int ret, val;
> > +       struct device *dev = &ctx->client->dev;
> > +       u8 ident[32];
> > +
> > +       ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +                               FLASH_ADDR_HIGH, 0x91);
> > +       ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +                                FLASH_ADDR_LOW, 0xA0);
> > +       if (ret < 0) {
> > +               DRM_DEV_ERROR(dev, "IO error : set key flash address.\n");
> > +               return ret;
> > +       }
> > +
> > +       ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +                               FLASH_LEN_HIGH, (FLASH_BUF_LEN - 1) >> 8);
> > +       ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +                                FLASH_LEN_LOW, (FLASH_BUF_LEN - 1) & 0xFF);
> > +       if (ret < 0) {
> > +               DRM_DEV_ERROR(dev, "IO error : set key flash len.\n");
> > +               return ret;
> > +       }
> > +
> > +       ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
> > +                               R_FLASH_RW_CTRL, FLASH_READ);
> > +       ret |= readx_poll_timeout(anx7625_read_flash_status,
> > +                                 ctx, val,
> > +                                 ((val & FLASH_DONE) || (val < 0)),
> > +                                 2000,
> > +                                 2000 * 150);
> > +       if (ret) {
> > +               DRM_DEV_ERROR(dev, "flash read access fail!\n");
> > +               return -EIO;
> > +       }
> > +
> > +       ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client,
> > +                                    FLASH_BUF_BASE_ADDR,
> > +                                    FLASH_BUF_LEN, ident);
> > +       if (ret < 0) {
> > +               DRM_DEV_ERROR(dev, "read flash data fail!\n");
> > +               return -EIO;
> > +       }
> > +
> > +       if (ident[29] == 0xFF && ident[30] == 0xFF && ident[31] == 0xFF)
> > +               return -EINVAL;
> > +
> > +       return 0;
> > +}
> > +
> > +static int anx7625_hdcp_setting(struct anx7625_data *ctx)
> > +{
> > +       u8 bcap;
> > +       int ret;
> > +       struct device *dev = &ctx->client->dev;
> > +
> > +       ret = anx7625_hdcp_key_probe(ctx);
> > +       if (ret) {
> > +               DRM_DEV_DEBUG_DRIVER(dev, "disable HDCP by config\n");
> > +               return anx7625_write_and(ctx, ctx->i2c.rx_p1_client,
> > +                                        0xee, 0x9f);
> > +       }
> > +
> > +       anx7625_aux_dpcd_read(ctx, 0x06, 0x80, 0x28, 1, &bcap);
> > +       if (!(bcap & 0x01)) {
> > +               DRM_DEV_DEBUG_DRIVER(dev, "bcap(0x%x) not support HDCP 1.4.\n",
> > +                                    bcap);
> > +               return anx7625_write_and(ctx, ctx->i2c.rx_p1_client,
> > +                                        0xee, 0x9f);
> > +       }
> > +
> > +       DRM_DEV_DEBUG_DRIVER(dev, "enable HDCP 1.4\n");
> > +
> > +       ret = anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xee, 0x20);
> > +
> > +       /* Try auth flag */
> > +       ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xec, 0x10);
> > +       /* Interrupt for DRM */
> > +       ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xff, 0x01);
> > +       if (ret < 0)
> > +               DRM_DEV_ERROR(dev, "fail to enable HDCP\n");
> > +
> > +       return ret;
> > +}
> > +
> >  static void anx7625_dp_start(struct anx7625_data *ctx)
> >  {
> >         int ret;
> > @@ -643,6 +787,9 @@ static void anx7625_dp_start(struct anx7625_data *ctx)
> >                 return;
> >         }
> >
> > +       /* HDCP config */
> > +       anx7625_hdcp_setting(ctx);
> 
> You should really use the "Content Protection" property to
> enable/disable HDCP instead of force-enabling it at all times.
> 
> Sean
Hi Sean, it's hard to implement "Content Protection" property, we have
implemented HDCP in firmware, it is not compatible with it. We don't
have interface to get Downstream Cert.
Thanks,
Xin
> 
> > +
> >         if (ctx->pdata.is_dpi)
> >                 ret = anx7625_dpi_config(ctx);
> >         else
> > diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h
> > index beee95da2155..c6f93e4df0ed 100644
> > --- a/drivers/gpu/drm/bridge/analogix/anx7625.h
> > +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h
> > @@ -154,9 +154,45 @@
> >
> >  #define  I2C_ADDR_7E_FLASH_CONTROLLER  0x7E
> >
> > +#define FLASH_SRAM_SEL          0x00
> > +#define SRAM_ADDR_HIGH          0x01
> > +#define SRAM_ADDR_LOW           0x02
> > +#define SRAM_LEN_HIGH           0x03
> > +#define SRAM_LEN_LOW            0x04
> >  #define FLASH_LOAD_STA          0x05
> >  #define FLASH_LOAD_STA_CHK     BIT(7)
> >
> > +#define R_RAM_CTRL              0x05
> > +/* bit positions */
> > +#define FLASH_DONE              BIT(7)
> > +#define BOOT_LOAD_DONE          BIT(6)
> > +#define CRC_OK                  BIT(5)
> > +#define LOAD_DONE               BIT(4)
> > +#define O_RW_DONE               BIT(3)
> > +#define FUSE_BUSY               BIT(2)
> > +#define DECRYPT_EN              BIT(1)
> > +#define LOAD_START              BIT(0)
> > +
> > +#define FLASH_ADDR_HIGH         0x0F
> > +#define FLASH_ADDR_LOW          0x10
> > +#define FLASH_LEN_HIGH          0x31
> > +#define FLASH_LEN_LOW           0x32
> > +
> > +#define R_FLASH_RW_CTRL         0x33
> > +/* bit positions */
> > +#define READ_DELAY_SELECT       BIT(7)
> > +#define GENERAL_INSTRUCTION_EN  BIT(6)
> > +#define FLASH_ERASE_EN          BIT(5)
> > +#define RDID_READ_EN            BIT(4)
> > +#define REMS_READ_EN            BIT(3)
> > +#define WRITE_STATUS_EN         BIT(2)
> > +#define FLASH_READ              BIT(1)
> > +#define FLASH_WRITE             BIT(0)
> > +
> > +#define FLASH_BUF_BASE_ADDR     0x60
> > +#define FLASH_BUF_LEN           0x20
> > +#define FLASH_KEY_OFFSET        0x8000
> > +
> >  #define  XTAL_FRQ_SEL    0x3F
> >  /* bit field positions */
> >  #define  XTAL_FRQ_SEL_POS    5
> > --
> > 2.25.1
> >
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
Sean Paul March 29, 2021, 6:02 p.m. UTC | #3
On Mon, Mar 29, 2021 at 6:27 AM Xin Ji <xji@analogixsemi.com> wrote:
>
> On Thu, Mar 25, 2021 at 02:19:23PM -0400, Sean Paul wrote:
> > On Fri, Mar 19, 2021 at 2:35 AM Xin Ji <xji@analogixsemi.com> wrote:
> > >
> > > Add HDCP feature, enable HDCP function through chip internal key
> > > and downstream's capability.
> > >
> > > Signed-off-by: Xin Ji <xji@analogixsemi.com>
> > > ---

/snip

> > >  static void anx7625_dp_start(struct anx7625_data *ctx)
> > >  {
> > >         int ret;
> > > @@ -643,6 +787,9 @@ static void anx7625_dp_start(struct anx7625_data *ctx)
> > >                 return;
> > >         }
> > >
> > > +       /* HDCP config */
> > > +       anx7625_hdcp_setting(ctx);
> >
> > You should really use the "Content Protection" property to
> > enable/disable HDCP instead of force-enabling it at all times.
> >
> > Sean
> Hi Sean, it's hard to implement "Content Protection" property, we have
> implemented HDCP in firmware, it is not compatible with it. We don't
> have interface to get Downstream Cert.
> Thanks,
> Xin

Hi Xin,
I'm sorry, I don't understand what you mean when you say you don't
have an interface to get Downstream Cert.

The Content Protection property is just a means through which
userspace can turn on and turn off HDCP when it needs. As far as I can
tell, your patch turns on HDCP when the display is enabled and leaves
it on until it is disabled. This is undesirable since it forces HDCP
on the user.

Is it impossible to enable/disable HDCP outside of display
enable/disable on your hardware?

Thanks,

Sean

> >
> > > +
> > >         if (ctx->pdata.is_dpi)
> > >                 ret = anx7625_dpi_config(ctx);
> > >         else

/snip
Xin Ji April 2, 2021, 2:27 a.m. UTC | #4
On Mon, Mar 29, 2021 at 02:02:08PM -0400, Sean Paul wrote:
> On Mon, Mar 29, 2021 at 6:27 AM Xin Ji <xji@analogixsemi.com> wrote:
> >
> > On Thu, Mar 25, 2021 at 02:19:23PM -0400, Sean Paul wrote:
> > > On Fri, Mar 19, 2021 at 2:35 AM Xin Ji <xji@analogixsemi.com> wrote:
> > > >
> > > > Add HDCP feature, enable HDCP function through chip internal key
> > > > and downstream's capability.
> > > >
> > > > Signed-off-by: Xin Ji <xji@analogixsemi.com>
> > > > ---
> 
> /snip
> 
> > > >  static void anx7625_dp_start(struct anx7625_data *ctx)
> > > >  {
> > > >         int ret;
> > > > @@ -643,6 +787,9 @@ static void anx7625_dp_start(struct anx7625_data *ctx)
> > > >                 return;
> > > >         }
> > > >
> > > > +       /* HDCP config */
> > > > +       anx7625_hdcp_setting(ctx);
> > >
> > > You should really use the "Content Protection" property to
> > > enable/disable HDCP instead of force-enabling it at all times.
> > >
> > > Sean
> > Hi Sean, it's hard to implement "Content Protection" property, we have
> > implemented HDCP in firmware, it is not compatible with it. We don't
> > have interface to get Downstream Cert.
> > Thanks,
> > Xin
> 
> Hi Xin,
> I'm sorry, I don't understand what you mean when you say you don't
> have an interface to get Downstream Cert.
> 
> The Content Protection property is just a means through which
> userspace can turn on and turn off HDCP when it needs. As far as I can
> tell, your patch turns on HDCP when the display is enabled and leaves
> it on until it is disabled. This is undesirable since it forces HDCP
> on the user.
> 
> Is it impossible to enable/disable HDCP outside of display
> enable/disable on your hardware?
> 
> Thanks,
> 
> Sean
Hi Sean, I have commit a test patch on google review site, can you
please help to review it? I'll use Connector's ".atomic_check()"
interface to detect Content Protection property change.
(https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/2674580)
Thanks,
Xin
> 
> > >
> > > > +
> > > >         if (ctx->pdata.is_dpi)
> > > >                 ret = anx7625_dpi_config(ctx);
> > > >         else
> 
> /snip
Laurent Pinchart April 2, 2021, 8:59 a.m. UTC | #5
Hi Xin,

On Fri, Apr 02, 2021 at 10:27:08AM +0800, Xin Ji wrote:
> On Mon, Mar 29, 2021 at 02:02:08PM -0400, Sean Paul wrote:
> > On Mon, Mar 29, 2021 at 6:27 AM Xin Ji <xji@analogixsemi.com> wrote:
> > >
> > > On Thu, Mar 25, 2021 at 02:19:23PM -0400, Sean Paul wrote:
> > > > On Fri, Mar 19, 2021 at 2:35 AM Xin Ji <xji@analogixsemi.com> wrote:
> > > > >
> > > > > Add HDCP feature, enable HDCP function through chip internal key
> > > > > and downstream's capability.
> > > > >
> > > > > Signed-off-by: Xin Ji <xji@analogixsemi.com>
> > > > > ---
> > 
> > /snip
> > 
> > > > >  static void anx7625_dp_start(struct anx7625_data *ctx)
> > > > >  {
> > > > >         int ret;
> > > > > @@ -643,6 +787,9 @@ static void anx7625_dp_start(struct anx7625_data *ctx)
> > > > >                 return;
> > > > >         }
> > > > >
> > > > > +       /* HDCP config */
> > > > > +       anx7625_hdcp_setting(ctx);
> > > >
> > > > You should really use the "Content Protection" property to
> > > > enable/disable HDCP instead of force-enabling it at all times.
> > >
> > > Hi Sean, it's hard to implement "Content Protection" property, we have
> > > implemented HDCP in firmware, it is not compatible with it. We don't
> > > have interface to get Downstream Cert.
> > > Thanks,
> > > Xin
> > 
> > Hi Xin,
> > I'm sorry, I don't understand what you mean when you say you don't
> > have an interface to get Downstream Cert.
> > 
> > The Content Protection property is just a means through which
> > userspace can turn on and turn off HDCP when it needs. As far as I can
> > tell, your patch turns on HDCP when the display is enabled and leaves
> > it on until it is disabled. This is undesirable since it forces HDCP
> > on the user.
> > 
> > Is it impossible to enable/disable HDCP outside of display
> > enable/disable on your hardware?
>
> Hi Sean, I have commit a test patch on google review site, can you
> please help to review it? I'll use Connector's ".atomic_check()"
> interface to detect Content Protection property change.
> (https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/2674580)

Please note that upstream review happens on mailing lists, not in
gerrit. Internal reviews for Chrome OS development are certainly fine
there, but that will not mean the patch will then be accepted upstream
as-is, it will still need to go through the upstream review process,
without any shortcut. I strongly recommend using an upstream-first
strategy, with public review.

> > > > > +
> > > > >         if (ctx->pdata.is_dpi)
> > > > >                 ret = anx7625_dpi_config(ctx);
> > > > >         else
> > 
> > /snip
Xin Ji April 2, 2021, 9:15 a.m. UTC | #6
On Fri, Apr 02, 2021 at 11:59:39AM +0300, Laurent Pinchart wrote:
> Hi Xin,
> 
> On Fri, Apr 02, 2021 at 10:27:08AM +0800, Xin Ji wrote:
> > On Mon, Mar 29, 2021 at 02:02:08PM -0400, Sean Paul wrote:
> > > On Mon, Mar 29, 2021 at 6:27 AM Xin Ji <xji@analogixsemi.com> wrote:
> > > >
> > > > On Thu, Mar 25, 2021 at 02:19:23PM -0400, Sean Paul wrote:
> > > > > On Fri, Mar 19, 2021 at 2:35 AM Xin Ji <xji@analogixsemi.com> wrote:
> > > > > >
> > > > > > Add HDCP feature, enable HDCP function through chip internal key
> > > > > > and downstream's capability.
> > > > > >
> > > > > > Signed-off-by: Xin Ji <xji@analogixsemi.com>
> > > > > > ---
> > > 
> > > /snip
> > > 
> > > > > >  static void anx7625_dp_start(struct anx7625_data *ctx)
> > > > > >  {
> > > > > >         int ret;
> > > > > > @@ -643,6 +787,9 @@ static void anx7625_dp_start(struct anx7625_data *ctx)
> > > > > >                 return;
> > > > > >         }
> > > > > >
> > > > > > +       /* HDCP config */
> > > > > > +       anx7625_hdcp_setting(ctx);
> > > > >
> > > > > You should really use the "Content Protection" property to
> > > > > enable/disable HDCP instead of force-enabling it at all times.
> > > >
> > > > Hi Sean, it's hard to implement "Content Protection" property, we have
> > > > implemented HDCP in firmware, it is not compatible with it. We don't
> > > > have interface to get Downstream Cert.
> > > > Thanks,
> > > > Xin
> > > 
> > > Hi Xin,
> > > I'm sorry, I don't understand what you mean when you say you don't
> > > have an interface to get Downstream Cert.
> > > 
> > > The Content Protection property is just a means through which
> > > userspace can turn on and turn off HDCP when it needs. As far as I can
> > > tell, your patch turns on HDCP when the display is enabled and leaves
> > > it on until it is disabled. This is undesirable since it forces HDCP
> > > on the user.
> > > 
> > > Is it impossible to enable/disable HDCP outside of display
> > > enable/disable on your hardware?
> >
> > Hi Sean, I have commit a test patch on google review site, can you
> > please help to review it? I'll use Connector's ".atomic_check()"
> > interface to detect Content Protection property change.
> > (https://nam10.safelinks.protection.outlook.com/?url=https%3A%2F%2Fchromium-review.googlesource.com%2Fc%2Fchromiumos%2Fthird_party%2Fkernel%2F%2B%2F2674580&amp;data=04%7C01%7Cxji%40analogixsemi.com%7Cd778885f3d0d4b4358a908d8f5b5c273%7Cb099b0b4f26c4cf59a0fd5be9acab205%7C0%7C0%7C637529508334886979%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=vo8zP8SAhLrQk0%2FWh1OhXHAZzLU9lJ4NLaYddI6t2ZU%3D&amp;reserved=0)
> 
> Please note that upstream review happens on mailing lists, not in
> gerrit. Internal reviews for Chrome OS development are certainly fine
> there, but that will not mean the patch will then be accepted upstream
> as-is, it will still need to go through the upstream review process,
> without any shortcut. I strongly recommend using an upstream-first
> strategy, with public review.
Hi Laurent Pinchart, OK, got it, thanks for the note.

Thanks,
Xin
> 
> > > > > > +
> > > > > >         if (ctx->pdata.is_dpi)
> > > > > >                 ret = anx7625_dpi_config(ctx);
> > > > > >         else
> > > 
> > > /snip
> 
> -- 
> Regards,
> 
> Laurent Pinchart
diff mbox series

Patch

diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c
index 8c514b46d361..b424a570effa 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -633,6 +633,150 @@  static int anx7625_dpi_config(struct anx7625_data *ctx)
 	return ret;
 }
 
+static int anx7625_aux_dpcd_read(struct anx7625_data *ctx,
+				 u8 addrh, u8 addrm, u8 addrl,
+				 u8 len, u8 *buf)
+{
+	struct device *dev = &ctx->client->dev;
+	int ret;
+	u8 cmd;
+
+	if (len > MAX_DPCD_BUFFER_SIZE) {
+		DRM_DEV_ERROR(dev, "exceed aux buffer len.\n");
+		return -E2BIG;
+	}
+
+	cmd = ((len - 1) << 4) | 0x09;
+
+	/* Set command and length */
+	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
+				AP_AUX_COMMAND, cmd);
+
+	/* Set aux access address */
+	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
+				 AP_AUX_ADDR_7_0, addrl);
+	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
+				 AP_AUX_ADDR_15_8, addrm);
+	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
+				 AP_AUX_ADDR_19_16, addrh);
+
+	/* Enable aux access */
+	ret |= anx7625_write_or(ctx, ctx->i2c.rx_p0_client,
+				AP_AUX_CTRL_STATUS, AP_AUX_CTRL_OP_EN);
+
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev, "cannot access aux related register.\n");
+		return -EIO;
+	}
+
+	usleep_range(2000, 2100);
+
+	ret = wait_aux_op_finish(ctx);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "aux IO error: wait aux op finish.\n");
+		return ret;
+	}
+
+	ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client,
+				     AP_AUX_BUFF_START, len, buf);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev, "read dpcd register failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int anx7625_read_flash_status(struct anx7625_data *ctx)
+{
+	return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, R_RAM_CTRL);
+}
+
+static int anx7625_hdcp_key_probe(struct anx7625_data *ctx)
+{
+	int ret, val;
+	struct device *dev = &ctx->client->dev;
+	u8 ident[32];
+
+	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
+				FLASH_ADDR_HIGH, 0x91);
+	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
+				 FLASH_ADDR_LOW, 0xA0);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev, "IO error : set key flash address.\n");
+		return ret;
+	}
+
+	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
+				FLASH_LEN_HIGH, (FLASH_BUF_LEN - 1) >> 8);
+	ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
+				 FLASH_LEN_LOW, (FLASH_BUF_LEN - 1) & 0xFF);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev, "IO error : set key flash len.\n");
+		return ret;
+	}
+
+	ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client,
+				R_FLASH_RW_CTRL, FLASH_READ);
+	ret |= readx_poll_timeout(anx7625_read_flash_status,
+				  ctx, val,
+				  ((val & FLASH_DONE) || (val < 0)),
+				  2000,
+				  2000 * 150);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "flash read access fail!\n");
+		return -EIO;
+	}
+
+	ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client,
+				     FLASH_BUF_BASE_ADDR,
+				     FLASH_BUF_LEN, ident);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev, "read flash data fail!\n");
+		return -EIO;
+	}
+
+	if (ident[29] == 0xFF && ident[30] == 0xFF && ident[31] == 0xFF)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int anx7625_hdcp_setting(struct anx7625_data *ctx)
+{
+	u8 bcap;
+	int ret;
+	struct device *dev = &ctx->client->dev;
+
+	ret = anx7625_hdcp_key_probe(ctx);
+	if (ret) {
+		DRM_DEV_DEBUG_DRIVER(dev, "disable HDCP by config\n");
+		return anx7625_write_and(ctx, ctx->i2c.rx_p1_client,
+					 0xee, 0x9f);
+	}
+
+	anx7625_aux_dpcd_read(ctx, 0x06, 0x80, 0x28, 1, &bcap);
+	if (!(bcap & 0x01)) {
+		DRM_DEV_DEBUG_DRIVER(dev, "bcap(0x%x) not support HDCP 1.4.\n",
+				     bcap);
+		return anx7625_write_and(ctx, ctx->i2c.rx_p1_client,
+					 0xee, 0x9f);
+	}
+
+	DRM_DEV_DEBUG_DRIVER(dev, "enable HDCP 1.4\n");
+
+	ret = anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xee, 0x20);
+
+	/* Try auth flag */
+	ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xec, 0x10);
+	/* Interrupt for DRM */
+	ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xff, 0x01);
+	if (ret < 0)
+		DRM_DEV_ERROR(dev, "fail to enable HDCP\n");
+
+	return ret;
+}
+
 static void anx7625_dp_start(struct anx7625_data *ctx)
 {
 	int ret;
@@ -643,6 +787,9 @@  static void anx7625_dp_start(struct anx7625_data *ctx)
 		return;
 	}
 
+	/* HDCP config */
+	anx7625_hdcp_setting(ctx);
+
 	if (ctx->pdata.is_dpi)
 		ret = anx7625_dpi_config(ctx);
 	else
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h
index beee95da2155..c6f93e4df0ed 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.h
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.h
@@ -154,9 +154,45 @@ 
 
 #define  I2C_ADDR_7E_FLASH_CONTROLLER  0x7E
 
+#define FLASH_SRAM_SEL          0x00
+#define SRAM_ADDR_HIGH          0x01
+#define SRAM_ADDR_LOW           0x02
+#define SRAM_LEN_HIGH           0x03
+#define SRAM_LEN_LOW            0x04
 #define FLASH_LOAD_STA          0x05
 #define FLASH_LOAD_STA_CHK	BIT(7)
 
+#define R_RAM_CTRL              0x05
+/* bit positions */
+#define FLASH_DONE              BIT(7)
+#define BOOT_LOAD_DONE          BIT(6)
+#define CRC_OK                  BIT(5)
+#define LOAD_DONE               BIT(4)
+#define O_RW_DONE               BIT(3)
+#define FUSE_BUSY               BIT(2)
+#define DECRYPT_EN              BIT(1)
+#define LOAD_START              BIT(0)
+
+#define FLASH_ADDR_HIGH         0x0F
+#define FLASH_ADDR_LOW          0x10
+#define FLASH_LEN_HIGH          0x31
+#define FLASH_LEN_LOW           0x32
+
+#define R_FLASH_RW_CTRL         0x33
+/* bit positions */
+#define READ_DELAY_SELECT       BIT(7)
+#define GENERAL_INSTRUCTION_EN  BIT(6)
+#define FLASH_ERASE_EN          BIT(5)
+#define RDID_READ_EN            BIT(4)
+#define REMS_READ_EN            BIT(3)
+#define WRITE_STATUS_EN         BIT(2)
+#define FLASH_READ              BIT(1)
+#define FLASH_WRITE             BIT(0)
+
+#define FLASH_BUF_BASE_ADDR     0x60
+#define FLASH_BUF_LEN           0x20
+#define FLASH_KEY_OFFSET        0x8000
+
 #define  XTAL_FRQ_SEL    0x3F
 /* bit field positions */
 #define  XTAL_FRQ_SEL_POS    5