RE: [PATCH v7 00/11] usb: musb: adding multi instance support

2012-08-03 Thread Ajay Gupta
Hi,
> On 03.08.2012 02:54, B, Ravi wrote:
> >> On 02.08.2012 14:12, Ravi Babu wrote:
> >>> This series of patches adds,
> >>> a) Multi instances support in musb driver
> >>> b) DT support for musb_dsps glue layer
> >>> c) DT support for NOP transceiver
> >>>
> >>> AM33xx and TI81xx has dual musb controller and has two usb
> >> PHY of same type.
> >>> This patch series uses 'phandle' based API
> >>> devm_usb_get_phy_by_phandle() to get the PHY of same type. This API
> >>> support is being added by Kishon's patch discussed at [1]
> >>>
> >>> The series applies to linux-omap (master branch)
> >>>   + Vaibhav baseport patches on his tree at [3]
> >>>   + Kishon's multi phy patches on Felipe's branch 'xceiv'
> >>>   + Kishon's patch on phandle at [1]
> >>>   + AM33xx musb glue compile and bugfix patches at [4],
> >> [5], [6] and [7]
> >>>   + Damodar's recent patch at [2]
> >>>
> >>> and have been tested on Beaglebone board.
> >
> > Have you applied the above patches before applying these patches.
> 
> Somehow, I was missing some of Ajay's patches. I resolved that, and now the
> series applied.
> 
> However, I needed to add a phandle "usb0-phy = <&usb0_phy>" to the
> usb_otg_hs DTSI block, otherwise devm_usb_get_phy_by_phandle() in
> drivers/usb/musb/musb_dsps.c would fail. Is that correct? I can't seem to
> find that in your patches.

It's getting done in patch 11/11.

> 
> With this addition, I see the following:
> 
> [1.782180] musb-hdrc: version 6.0, ?dma?, otg (peripheral+host)
> [1.809966] musb-hdrc musb-hdrc.0: MUSB HDRC host driver
> [1.819068] musb-hdrc musb-hdrc.0: new USB bus registered, assigned
> bus number 1
> [1.827970] usb usb1: New USB device found, idVendor=1d6b,
> idProduct=0002
> [1.835184] usb usb1: New USB device strings: Mfr=3, Product=2,
> SerialNumber=1
> [1.842818] usb usb1: Product: MUSB HDRC host driver
> [1.848031] usb usb1: Manufacturer: Linux
> 3.6.0-rc1-00038-g8a1ec8f-dirty musb-hcd
> [1.855933] usb usb1: SerialNumber: musb-hdrc.0
> [1.866913] hub 1-0:1.0: USB hub found
> [1.871192] hub 1-0:1.0: 1 port detected
> [1.878106] musb-hdrc musb-hdrc.0: USB Host mode controller at
> d08c using PIO, IRQ 18
> 
> ... but no USB functions. Also, every two seconds, the following message is
> printed:
> 
> [   11.036608] musb_bus_suspend 2308: trying to suspend as a_wait_vrise
> while active
> [   13.044811] musb_bus_suspend 2308: trying to suspend as a_wait_vrise
> while active
> [   15.052196] musb_bus_suspend 2308: trying to suspend as a_wait_vrise
> while active

Do you see them even when you connect a device to port?

Ajay
> 
> 
> Anything obvious that I'm missing?
> 
> 
> Thanks,
> Daniel
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in the
> body of a message to majord...@vger.kernel.org More majordomo info at
> http://vger.kernel.org/majordomo-info.html
---
This email message is for the sole use of the intended recipient(s) and may 
contain
confidential information.  Any unauthorized review, use, disclosure or 
distribution
is prohibited.  If you are not the intended recipient, please contact the 
sender by
reply email and destroy all copies of the original message.
---
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


XHCI: URB not cancelled during disconnect of a MSC device

2012-09-12 Thread Ajay Gupta
Hi,

I am using v3.5 kernel and running a test where I disconnect a SS MSC
device while a big file is being written to it. I am also watching the
lsusb output in parallel. Expectation is that SS MSC device should
immediately disappear from lsusb output but sometime I see that SS MSC
is listed for 30 seconds and then only disappears. Log is copied
below.

Looking further into the issue shows that in failing case an URB is
not given back by XHCI driver and so SCSI layer unlinks it after
30second of timeout. This URB was actually given to XHCI host
controller and a disconnect happens while packet transfer was in
progress. I looked at XHCI driver and could not find request being
aborted by driver (in xhci_free_dev() fn) before issuing disable slot
or reset device command. What is expectation in this scenario? Is it
XHCI driver responsibility to abort and giveback all the request (as
in EHCI using endpoint_disable()) OR host controller hardware should
abort and post an error completion event for each request? Why XHCI
driver doesn't have an endpoint_disable() implemented as done for
other controller?

=== Working case 
[ 3406.676989] Port Status Change Event for port 2
[ 3406.711530] get port status, actual port 1 status = 0x4202c0
[ 3406.711531] Get port status returned 0x4102c0
[ 3406.711629] clear port connect change, actual port 1 status = 0x4002c0
[ 3406.711664] clear port link state change, actual port 1 status = 0x2c0
[ 3406.721606] [E.f2e0b980.Transfer error on endpoint  <=== URB
submitted here but gets transfer error
[ 3406.721742] Cleaning up stalled endpoint ring
[ 3406.721744] Finding segment containing stopped TRB.
[ 3406.721746] Finding endpoint context
[ 3406.721747] Finding segment containing last TRB in TD.
[ 3406.721749] Cycle state = 0x1
[ 3406.721750] New dequeue segment = f2073880 (virtual)
[ 3406.721752] New dequeue pointer = 0x337be380 (DMA)
[ 3406.721754] Queueing new dequeue state
[ 3406.721756] Set TR Deq Ptr cmd, new deq seg = f2073880 (0x337be000
dma), new deq ptr = f37be380 (0x337be380 dma), new cycle = 1
[ 3406.721758]// Ding dong!
[ 3406.721855] Giveback URB f2e0b980, len = 0, expected = 31, status =
-71  <=== URB given back by XHCI driver
=


=== Non Working case 
[ 2971.576389] Port Status Change Event for port 2
[ 2971.576487] [E.f2d0c480.   <=== URB submitted but no error.
[ 2971.585007] get port status, actual port 1 status = 0x4202c0
[ 2971.585079] Get port status returned 0x4102c0
[ 2971.585178] clear port connect change, actual port 1 status = 0x4002c0
[ 2971.585213] clear port link state change, actual port 1 status = 0x2c0
[ 2971.640030] get port status, actual port 1 status = 0x2d1
[ 2971.640031] Get port status returned 0x2d1
[ 2971.696029] get port status, actual port 1 status = 0x2d1
[ 2971.696031] Get port status returned 0x2d1
[ 2971.900031] get port status, actual port 1 status = 0x2d1
[ 2971.900034] Get port status returned 0x2d1
[ 2972.060480] Port Status Change Event for port 2
[ 2972.104039] get port status, actual port 1 status = 0x2802a0
[ 2972.104041] Get port status returned 0x3002a0
[ 2972.104079] clear port reset change, actual port 1 status = 0x802a0
[ 2972.104108] clear port warm(BH) reset change, actual port 1 status = 0x2a0
[ 2972.104138] clear port link state change, actual port 1 status = 0x2a0
[ 2972.104144] usb 6-2: USB disconnect, device number 6

<=== 30 seconds gap  >

[ 3002.080058] Cancel URB f2d0c480, dev 2, ep 0x81, starting at offset
0x337ad060   <== SCSI layer cancelling URB after 30 seconds
[ 3002.080063]// Ding dong!
[ 2972.060569] Stopped on Transfer TRB
[ 3002.080817] Removing canceled TD starting at 0x337ad060 (dma).
[ 3002.080820] Finding segment containing stopped TRB.
[ 3002.080822] Finding endpoint context
[ 3002.080823] Finding segment containing last TRB in TD.
[ 3002.080825] Cycle state = 0x0
[ 3002.080827] New dequeue segment = f71628f0 (virtual)
[ 3002.080828] New dequeue pointer = 0x337ad070 (DMA)
[ 3002.080831] Set TR Deq Ptr cmd, new deq seg = f71628f0 (0x337ad000
dma), new deq ptr = f37ad070 (0x337ad070 dma), new cycle = 0

=

Thanks
Ajay
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: XHCI: URB not cancelled during disconnect of a MSC device

2012-09-12 Thread Ajay Gupta
Hi,
>> I am using v3.5 kernel and running a test where I disconnect
>> a SS MSC device while a big file is being written to it. I am
>> also watching the lsusb output in parallel. Expectation is
>> that SS MSC device should immediately disappear from lsusb
>> output but sometime I see that SS MSC is listed for 30
>> seconds and then only disappears. Log is copied below.
>>
>> Looking further into the issue shows that in failing case an
>> URB is not given back by XHCI driver and so SCSI layer
>> unlinks it after 30second of timeout. This URB was actually
>> given to XHCI host controller and a disconnect happens while
>> packet transfer was in progress. I looked at XHCI driver and
>> could not find request being aborted by driver (in
>> xhci_free_dev() fn) before issuing disable slot or reset
>> device command. What is expectation in this scenario? Is it
>> XHCI driver responsibility to abort and giveback all the
>> request (as in EHCI using endpoint_disable()) OR host
>> controller hardware should abort and post an error completion
>> event for each request? Why XHCI driver doesn't have an
>> endpoint_disable() implemented as done for other controller?
>>
>
> I have faced similar scenario, check whether patch 
> http://marc.info/?l=linux-usb&m=134382746009339&w=2could could help,
> Alan suggesting that hcd controller should release all URBs when device got 
> disconnected.

It didn't help.

Thanks,
Ajay
>
> -RaviBabu
>
>> === Working case  [
>> 3406.676989] Port Status Change Event for port 2 [
>> 3406.711530] get port status, actual port 1 status = 0x4202c0
>> [ 3406.711531] Get port status returned 0x4102c0 [
>> 3406.711629] clear port connect change, actual port 1 status
>> = 0x4002c0 [ 3406.711664] clear port link state change,
>> actual port 1 status = 0x2c0 [ 3406.721606]
>> [E.f2e0b980.Transfer error on endpoint  <=== URB submitted
>> here but gets transfer error [ 3406.721742] Cleaning up
>> stalled endpoint ring [ 3406.721744] Finding segment
>> containing stopped TRB.
>> [ 3406.721746] Finding endpoint context
>> [ 3406.721747] Finding segment containing last TRB in TD.
>> [ 3406.721749] Cycle state = 0x1
>> [ 3406.721750] New dequeue segment = f2073880 (virtual) [
>> 3406.721752] New dequeue pointer = 0x337be380 (DMA) [
>> 3406.721754] Queueing new dequeue state [ 3406.721756] Set TR
>> Deq Ptr cmd, new deq seg = f2073880 (0x337be000 dma), new deq
>> ptr = f37be380 (0x337be380 dma), new cycle = 1 [
>> 3406.721758]// Ding dong!
>> [ 3406.721855] Giveback URB f2e0b980, len = 0, expected = 31, status =
>> -71  <=== URB given back by XHCI driver
>> =
>>
>>
>> === Non Working case  [
>> 2971.576389] Port Status Change Event for port 2
>> [ 2971.576487] [E.f2d0c480.   <=== URB submitted but no error.
>> [ 2971.585007] get port status, actual port 1 status =
>> 0x4202c0 [ 2971.585079] Get port status returned 0x4102c0 [
>> 2971.585178] clear port connect change, actual port 1 status
>> = 0x4002c0 [ 2971.585213] clear port link state change,
>> actual port 1 status = 0x2c0 [ 2971.640030] get port status,
>> actual port 1 status = 0x2d1 [ 2971.640031] Get port status
>> returned 0x2d1 [ 2971.696029] get port status, actual port 1
>> status = 0x2d1 [ 2971.696031] Get port status returned 0x2d1
>> [ 2971.900031] get port status, actual port 1 status = 0x2d1
>> [ 2971.900034] Get port status returned 0x2d1 [ 2972.060480]
>> Port Status Change Event for port 2 [ 2972.104039] get port
>> status, actual port 1 status = 0x2802a0 [ 2972.104041] Get
>> port status returned 0x3002a0 [ 2972.104079] clear port reset
>> change, actual port 1 status = 0x802a0 [ 2972.104108] clear
>> port warm(BH) reset change, actual port 1 status = 0x2a0 [
>> 2972.104138] clear port link state change, actual port 1
>> status = 0x2a0 [ 2972.104144] usb 6-2: USB disconnect, device number 6
>>
>> <=== 30 seconds gap  >
>>
>> [ 3002.080058] Cancel URB f2d0c480, dev 2, ep 0x81, starting at offset
>> 0x337ad060   <== SCSI layer cancelling URB after 30 seconds
>> [ 3002.080063]// Ding dong!
>> [ 2972.060569] Stopped on Transfer TRB
>> [ 3002.080817] Removing canceled TD starting at 0x337ad060 (dma).
>> [ 3002.080820] Finding segment containing stopped TRB.
>> [ 3002.080822] Finding endpoint context
>> [ 3002.080823] Finding segment containing last TRB in TD.
>> [ 3002.080825] Cycle state = 0x0
>> [ 3002.080827] New dequeue segment = f71628f0 (virtual) [
>> 3002.080828] New dequeue pointer = 0x337ad070 (DMA) [
>> 3002.080831] Set TR Deq Ptr cmd, new deq seg = f71628f0
>> (0x337ad000 dma), new deq ptr = f37ad070 (0x337ad070 dma),
>> new cycle = 0
>>
>> =
>>
>> Thanks
>> Ajay
>> --
>> To unsubscribe from this list: send the line "unsubscribe
>> linux-usb" in the body of a message to
>> majord...@vger.kernel.org More majordomo info at
>> http://vger.kernel.org/majordomo-info.html
>>
--
T

Re: XHCI: URB not cancelled during disconnect of a MSC device

2012-09-13 Thread Ajay Gupta
Hi Sarah

On Thu, Sep 13, 2012 at 2:37 AM, Sarah Sharp
 wrote:
> On Wed, Sep 12, 2012 at 03:36:39PM +0530, Ajay Gupta wrote:
>> Hi,
>>
>> I am using v3.5 kernel and running a test where I disconnect a SS MSC
>> device while a big file is being written to it. I am also watching the
>> lsusb output in parallel. Expectation is that SS MSC device should
>> immediately disappear from lsusb output but sometime I see that SS MSC
>> is listed for 30 seconds and then only disappears. Log is copied
>> below.
>>
>> Looking further into the issue shows that in failing case an URB is
>> not given back by XHCI driver and so SCSI layer unlinks it after
>> 30second of timeout. This URB was actually given to XHCI host
>> controller and a disconnect happens while packet transfer was in
>> progress. I looked at XHCI driver and could not find request being
>> aborted by driver (in xhci_free_dev() fn) before issuing disable slot
>> or reset device command. What is expectation in this scenario?
>
> The expectation is that the mass storage driver should have aborted any
> URBs in its disconnect function before xhci_free_dev() is called.  I
> believe all USB drivers are required to do this.  If that assumption
> isn't true, then, yes, I need to revisit any place that xHCI rings get
> freed.

I think your assumption is correct and same has been discussed by Alan at
http://marc.info/?l=linux-usb&m=134382746009339&w=2could

The 30 seconds delay seems to be expected linux storage behavior as per
discussion in above thread.

I tested again with little modified version of code (copied below) suggested in
above link and don't see any issue. I understand that below code is a pure
hack and *not* a solution.

-
--- a/usb.c
+++ b/usb.c
@@ -834,6 +834,8 @@ static void quiesce_and_remove_host(struct us_data *us)
if (test_bit(US_FLIDX_SCAN_PENDING, &us->dflags))
usb_autopm_put_interface_no_suspend(us->pusb_intf);

+   /* stop the current urbs when the device got disconnected */
+   usb_stor_stop_transport(us);
/* Removing the host will perform an orderly shutdown: caches
 * synchronized, disks spun down, etc.
 */
-

Alan suggested to add logic inside host controller driver to unlink
all URBs at disconnect.
This is required as either SCSI or storage layer doesn't know if
device is unplugged or
unbounded.

Another solution could be to add some kind of flag notifying to SCSI
layer of device
disconnect or unbound and so SCSI layer shouldn't wait for 30 seconds if it's
disconnect.

>> Is it
>> XHCI driver responsibility to abort and giveback all the request (as
>> in EHCI using endpoint_disable())
>> Why XHCI
>> driver doesn't have an endpoint_disable() implemented as done for
>> other controller?
>
> The xHCI driver just works differently than EHCI.  It's not a
> requirement to implement the endpoint disable function, AFAIK.  From
> what I remember, the endpoint disable function was supposed to be used
> before switching alternate interface settings, but it was called too
> late to be of much use to the xHCI bandwidth functions.  So I created
> new bandwidth functions and ignored the endpoint disable functions.
> Maybe Alan can explain what the requirements about the endpoint disable
> function are?

endpoint_disbale is also called from usbcore layer in disconnect path.

>
>> OR host controller hardware should
>> abort and post an error completion event for each request?
>
> If the host controller hardware was in the middle of a transfer when the
> device was disconnected, and that caused the transfer to timeout, then,
> yes, the host should return an event with a transfer error and halt the
> event ring, as described in the xHCI 1.0 spec, section 4.10.2.3.  Even
> if the host wasn't strictly speaking in the middle of a transfer during
> the disconnect, the endpoint ring should remain on the host's schedule
> as long as the xHCI driver didn't issue a stop endpoint command.  I
> would expect that the transfer would timeout the next time it was
> executed from the schedule.
>
> Basically, the host controller has to play dumb and hand back events
> with error statuses for all TDs that continue to be schedulable after a
> device disconnect.  Eventually the USB core will notice the disconnect,
> notify the driver, and it will cancel any outstanding URBs.
>
>> === Working case 

[...]

>> dma), new deq ptr = f37ad070 (0x337ad070 dma), new cycle = 0
>
> According to that

Re: XHCI: URB not cancelled during disconnect of a MSC device

2012-09-13 Thread Ajay Gupta
Hi

>> >> I am using v3.5 kernel and running a test where I disconnect a SS MSC
>> >> device while a big file is being written to it. I am also watching the
>> >> lsusb output in parallel. Expectation is that SS MSC device should
>> >> immediately disappear from lsusb output but sometime I see that SS MSC
>> >> is listed for 30 seconds and then only disappears. Log is copied
>> >> below.
>> >>
>> >> Looking further into the issue shows that in failing case an URB is
>> >> not given back by XHCI driver and so SCSI layer unlinks it after
>> >> 30second of timeout. This URB was actually given to XHCI host
>> >> controller and a disconnect happens while packet transfer was in
>> >> progress. I looked at XHCI driver and could not find request being
>> >> aborted by driver (in xhci_free_dev() fn) before issuing disable slot
>> >> or reset device command. What is expectation in this scenario?
>> >
>> > The expectation is that the mass storage driver should have aborted any
>> > URBs in its disconnect function before xhci_free_dev() is called.  I
>> > believe all USB drivers are required to do this.  If that assumption
>> > isn't true, then, yes, I need to revisit any place that xHCI rings get
>> > freed.
>
> It's not that simple.
>
>> I think your assumption is correct and same has been discussed by Alan at
>> http://marc.info/?l=linux-usb&m=134382746009339&w=2could
>
> As discussed in that thread, the real requirement is that the host
> controller should complete URBs with an error if the device has
> disconnected (and therefore isn't sending any handshake packets).

Sarah,
Do you plan to add this support in XHCI driver?

>
>> Alan suggested to add logic inside host controller driver to unlink
>> all URBs at disconnect.
>
> No, that's not what I suggested.  I said that transfers should be
> aborted when the controller hardware detects that the device fails to
> send handshake packets.

Yes, I meant the same.

>
>> This is required as either SCSI or storage layer doesn't know if
>> device is unplugged or
>> unbounded.
>>
>> Another solution could be to add some kind of flag notifying to SCSI
>> layer of device
>> disconnect or unbound and so SCSI layer shouldn't wait for 30 seconds if it's
>> disconnect.
>
> Both of those solutions are inappropriate.

Aborting URBs from within HCD after device disconnect is appropriate. right?

Ajay
>
>> >> Is it
>> >> XHCI driver responsibility to abort and giveback all the request (as
>> >> in EHCI using endpoint_disable())
>> >> Why XHCI
>> >> driver doesn't have an endpoint_disable() implemented as done for
>> >> other controller?
>> >
>> > The xHCI driver just works differently than EHCI.  It's not a
>> > requirement to implement the endpoint disable function, AFAIK.  From
>> > what I remember, the endpoint disable function was supposed to be used
>> > before switching alternate interface settings, but it was called too
>> > late to be of much use to the xHCI bandwidth functions.  So I created
>> > new bandwidth functions and ignored the endpoint disable functions.
>> > Maybe Alan can explain what the requirements about the endpoint disable
>> > function are?
>
> THe endpoint_disable function doesn't have to do anything as far as
> usbcore is concerned.  It is a callback; it gives the HCD a chance to
> deallocate any internal data structures associated with the endpoint.
>
> When endpoint_disable is called there shouldn't be any URBs queued for
> the endpoint.  The core guarantees this by preventing new URBs from
> being accepted, unlinking all existing URBs, and then waiting for them
> to complete.
>
>> endpoint_disbale is also called from usbcore layer in disconnect path.
>>
>> >
>> >> OR host controller hardware should
>> >> abort and post an error completion event for each request?
>> >
>> > If the host controller hardware was in the middle of a transfer when the
>> > device was disconnected, and that caused the transfer to timeout, then,
>> > yes, the host should return an event with a transfer error and halt the
>> > event ring, as described in the xHCI 1.0 spec, section 4.10.2.3.  Even
>> > if the host wasn't strictly speaking in the middle of a transfer during
>> > the disconnect, the endpoint ring should remain on the host's schedule
>> > as long as the xHCI driver didn't issue a stop endpoint command.  I
>> > would expect that the transfer would timeout the next time it was
>> > executed from the schedule.
>
> If by "timeout" you mean fail under the "3 strikes" rule, then yes,
> this is what should happen.
>
> Alan Stern
>
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: XHCI: URB not cancelled during disconnect of a MSC device

2012-09-24 Thread Ajay Gupta
Hi,

> Ajay, which host controller are you seeing the disconnect lags on?  Can you
> send me the output of `sudo lspci -vvv -n`?

I was on leave last week so will  get the data at earliest.

Ajay
> 
> Sarah Sharp
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in the
> body of a message to majord...@vger.kernel.org More majordomo info at
> http://vger.kernel.org/majordomo-info.html
---
This email message is for the sole use of the intended recipient(s) and may 
contain
confidential information.  Any unauthorized review, use, disclosure or 
distribution
is prohibited.  If you are not the intended recipient, please contact the 
sender by
reply email and destroy all copies of the original message.
---
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


RE: [PATCH v2 0/2] usb: typec: ucsi: Support for DP alt mode

2019-03-25 Thread Ajay Gupta
Hi Heikki,

> -Original Message-
> From: linux-usb-ow...@vger.kernel.org  On
> Behalf Of Heikki Krogerus
> Sent: Wednesday, March 20, 2019 4:45 AM
> To: Ajay Gupta ; Michael Hsu 
> Cc: linux-usb@vger.kernel.org
> Subject: [PATCH v2 0/2] usb: typec: ucsi: Support for DP alt mode
> 
> Hi,
> 
> This is the second version of my proposal to add alt mode handling to ucsi 
> driver.
> The problem in the first version was that I was not using the port alt mode 
> that
> was associated with the partner alt mode (and vise versa), but I was instead
> searching the alt mode objects in every case separately.
> 
> So in this version I'm now always using the already associated alternate mode
> partner in every case, and as far as the UCSI driver (or any other USB Type-C
> driver) is concerned, that is all that it needs to do. The problem of actually
> associating the correct alt mode partner object belongs to the Type-C 
> subsystem
> core code, and any improvements to that code are out side of the scope of this
> series.
> 
> I've prepared a patch that allows the alt mode drivers to find the correct 
> port alt
> mode for the partner alt modes. That should cover SVIDs that define multiple
> modes (note, DisplayPort Alt mode is not one of those). But as I mentioned
> above, that is not related to this series.
Thanks for the new set. It looks good to me.
I tested it with UCSI CCG on NVIDIA GPU and it works.

Tested-By: Ajay Gupta 

Thanks
Ajay
>  nvpublic
> You can check the v1 from here:
> https://www.spinics.net/lists/linux-usb/msg176703.html
> 
> thanks,
> 
> Heikki Krogerus (2):
>   usb: typec: ucsi: Preliminary support for alternate modes
>   usb: typec: ucsi: Support for DisplayPort alt mode
> 
>  drivers/usb/typec/ucsi/Makefile  |  15 +-
>  drivers/usb/typec/ucsi/displayport.c | 297 ++
>  drivers/usb/typec/ucsi/trace.c   |  12 +
>  drivers/usb/typec/ucsi/trace.h   |  26 ++
>  drivers/usb/typec/ucsi/ucsi.c| 366 ++-
>  drivers/usb/typec/ucsi/ucsi.h|  93 +++
>  6 files changed, 738 insertions(+), 71 deletions(-)  create mode 100644
> drivers/usb/typec/ucsi/displayport.c
> 
> --
> 2.20.1



[PATCH 2/2] usb: typec: Add driver for NVIDIA Alt Modes

2019-04-10 Thread Ajay Gupta
From: Ajay Gupta 

Latest NVIDIA GPUs support VirtualLink device. Since USBIF
has not assigned a Standard ID (SID) for VirtualLink
so using NVIDA VID 0x955 as SVID.

Signed-off-by: Ajay Gupta 
---
 drivers/usb/typec/altmodes/Kconfig  | 10 +++
 drivers/usb/typec/altmodes/Makefile |  2 ++
 drivers/usb/typec/altmodes/nvidia.c | 44 +
 drivers/usb/typec/ucsi/ucsi.c   |  4 ++-
 include/linux/usb/typec_dp.h|  5 
 5 files changed, 64 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/typec/altmodes/nvidia.c

diff --git a/drivers/usb/typec/altmodes/Kconfig 
b/drivers/usb/typec/altmodes/Kconfig
index ef2226eb7a33..187690fd1a5b 100644
--- a/drivers/usb/typec/altmodes/Kconfig
+++ b/drivers/usb/typec/altmodes/Kconfig
@@ -12,4 +12,14 @@ config TYPEC_DP_ALTMODE
  To compile this driver as a module, choose M here: the
  module will be called typec_displayport.
 
+config TYPEC_NVIDIA_ALTMODE
+   tristate "NVIDIA Alternate Mode driver"
+   depends on TYPEC_DP_ALTMODE
+   help
+ Latest NVIDIA GPUs support VirtualLink devices. Select this
+ to enable support for VirtualLink devices with NVIDIA GPUs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called typec_displayport.
+
 endmenu
diff --git a/drivers/usb/typec/altmodes/Makefile 
b/drivers/usb/typec/altmodes/Makefile
index eda8456f1c92..45717548b396 100644
--- a/drivers/usb/typec/altmodes/Makefile
+++ b/drivers/usb/typec/altmodes/Makefile
@@ -2,3 +2,5 @@
 
 obj-$(CONFIG_TYPEC_DP_ALTMODE) += typec_displayport.o
 typec_displayport-y:= displayport.o
+obj-$(CONFIG_TYPEC_NVIDIA_ALTMODE) += typec_nvidia.o
+typec_nvidia-y := nvidia.o
diff --git a/drivers/usb/typec/altmodes/nvidia.c 
b/drivers/usb/typec/altmodes/nvidia.c
new file mode 100644
index ..c36769736405
--- /dev/null
+++ b/drivers/usb/typec/altmodes/nvidia.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 NVIDIA Corporation. All rights reserved.
+ *
+ * NVIDIA USB Type-C Alt Mode Driver
+ */
+#include 
+#include 
+#include 
+#include "displayport.h"
+
+static int nvidia_altmode_probe(struct typec_altmode *alt)
+{
+   if (alt->svid == USB_TYPEC_NVIDIA_VLINK_SID)
+   return dp_altmode_probe(alt);
+   else
+   return -ENOTSUPP;
+}
+
+static void nvidia_altmode_remove(struct typec_altmode *alt)
+{
+   if (alt->svid == USB_TYPEC_NVIDIA_VLINK_SID)
+   dp_altmode_remove(alt);
+}
+
+static const struct typec_device_id nvidia_typec_id[] = {
+   { USB_TYPEC_NVIDIA_VLINK_SID, TYPEC_ANY_MODE },
+   { },
+};
+MODULE_DEVICE_TABLE(typec, nvidia_typec_id);
+
+static struct typec_altmode_driver nvidia_altmode_driver = {
+   .id_table = nvidia_typec_id,
+   .probe = nvidia_altmode_probe,
+   .remove = nvidia_altmode_remove,
+   .driver = {
+   .name = "typec_nvidia",
+   .owner = THIS_MODULE,
+   },
+};
+module_typec_altmode_driver(nvidia_altmode_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("NVIDIA USB Type-C Alt Mode Driver");
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index 46feae074d8f..a8c8e66621ec 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -306,6 +306,7 @@ static int ucsi_register_altmode(struct ucsi_connector *con,
 
switch (desc->svid) {
case USB_TYPEC_DP_SID:
+   case USB_TYPEC_NVIDIA_VLINK_SID:
alt = ucsi_register_displayport(con, override, i, desc);
break;
default:
@@ -424,7 +425,8 @@ static void ucsi_unregister_altmodes(struct ucsi_connector 
*con, u8 recipient)
 
while (adev[i]) {
if (recipient == UCSI_RECIPIENT_SOP &&
-   adev[i]->svid == USB_TYPEC_DP_SID) {
+   (adev[i]->svid == USB_TYPEC_DP_SID ||
+   adev[i]->svid == USB_TYPEC_NVIDIA_VLINK_SID)) {
pdev = typec_altmode_get_partner(adev[i]);
ucsi_displayport_remove_partner((void *)pdev);
}
diff --git a/include/linux/usb/typec_dp.h b/include/linux/usb/typec_dp.h
index 7fa12ef8d09a..fc4c7edb2e8a 100644
--- a/include/linux/usb/typec_dp.h
+++ b/include/linux/usb/typec_dp.h
@@ -5,6 +5,11 @@
 #include 
 
 #define USB_TYPEC_DP_SID   0xff01
+/* USB IF has not assigned a Standard ID (SID) for VirtualLink,
+ * so the manufacturers of VirtualLink adapters use their Vendor
+ * IDs as the SVID.
+ */
+#define USB_TYPEC_NVIDIA_VLINK_SID 0x955   /* NVIDIA VirtualLink */
 #define USB_TYPEC_DP_MODE  1
 
 /*
-- 
2.17.1



[PATCH 1/2] usb: typec: displayport: Export probe and remove functions

2019-04-10 Thread Ajay Gupta
From: Heikki Krogerus 

VirtualLink standard extends the DisplayPort Alt Mode by
utilizing also the USB 2 pins on the USB Type-C connector.
It uses the same messages as DisplayPort, but not the DP
SVID. At the time of writing, USB IF has not assigned a
Standard ID (SID) for VirtualLink, so the manufacturers of
VirtualLink adapters use their Vendor IDs as the SVID.

Since the SVID specific communication is exactly the same as
with DisplayPort alternate mode, there is no need to
implement separate driver for VirtualLink. We'll handle the
current VirtualLink adapters with probe drivers, and once
there is SVID assigned for it, we add it to the displayport
alt mode driver.

To support probing drivers, exporting the probe and remove
functions, and also changing the DP_HEADER helper macro to
use the SVID of the alternate mode device instead of the
DisplayPort alt mode SVID.

[Fixed two warnings from checkpatch.pl script  -Ajay]
Signed-off-by: Heikki Krogerus 
Signed-off-by: Ajay Gupta 
Tested-by: Ajay Gupta 
---
 drivers/usb/typec/altmodes/displayport.c | 12 +++-
 drivers/usb/typec/altmodes/displayport.h |  8 
 2 files changed, 15 insertions(+), 5 deletions(-)
 create mode 100644 drivers/usb/typec/altmodes/displayport.h

diff --git a/drivers/usb/typec/altmodes/displayport.c 
b/drivers/usb/typec/altmodes/displayport.c
index 610d790bc9be..bbf317c838d3 100644
--- a/drivers/usb/typec/altmodes/displayport.c
+++ b/drivers/usb/typec/altmodes/displayport.c
@@ -14,7 +14,7 @@
 #include 
 #include 
 
-#define DP_HEADER(cmd) (VDO(USB_TYPEC_DP_SID, 1, cmd) | \
+#define DP_HEADER(_dp, cmd)(VDO((_dp)->alt->svid, 1, cmd) | \
 VDO_OPOS(USB_TYPEC_DP_MODE))
 
 enum {
@@ -155,7 +155,7 @@ static int dp_altmode_configured(struct dp_altmode *dp)
 
 static int dp_altmode_configure_vdm(struct dp_altmode *dp, u32 conf)
 {
-   u32 header = DP_HEADER(DP_CMD_CONFIGURE);
+   u32 header = DP_HEADER(dp, DP_CMD_CONFIGURE);
int ret;
 
ret = typec_altmode_notify(dp->alt, TYPEC_STATE_SAFE, &dp->data);
@@ -193,7 +193,7 @@ static void dp_altmode_work(struct work_struct *work)
dev_err(&dp->alt->dev, "failed to enter mode\n");
break;
case DP_STATE_UPDATE:
-   header = DP_HEADER(DP_CMD_STATUS_UPDATE);
+   header = DP_HEADER(dp, DP_CMD_STATUS_UPDATE);
vdo = 1;
ret = typec_altmode_vdm(dp->alt, header, &vdo, 2);
if (ret)
@@ -507,7 +507,7 @@ static const struct attribute_group dp_altmode_group = {
.attrs = dp_altmode_attrs,
 };
 
-static int dp_altmode_probe(struct typec_altmode *alt)
+int dp_altmode_probe(struct typec_altmode *alt)
 {
const struct typec_altmode *port = typec_altmode_get_partner(alt);
struct dp_altmode *dp;
@@ -545,14 +545,16 @@ static int dp_altmode_probe(struct typec_altmode *alt)
 
return 0;
 }
+EXPORT_SYMBOL_GPL(dp_altmode_probe);
 
-static void dp_altmode_remove(struct typec_altmode *alt)
+void dp_altmode_remove(struct typec_altmode *alt)
 {
struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
 
sysfs_remove_group(&alt->dev.kobj, &dp_altmode_group);
cancel_work_sync(&dp->work);
 }
+EXPORT_SYMBOL_GPL(dp_altmode_remove);
 
 static const struct typec_device_id dp_typec_id[] = {
{ USB_TYPEC_DP_SID, USB_TYPEC_DP_MODE },
diff --git a/drivers/usb/typec/altmodes/displayport.h 
b/drivers/usb/typec/altmodes/displayport.h
new file mode 100644
index ..e120364da9fd
--- /dev/null
+++ b/drivers/usb/typec/altmodes/displayport.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#if IS_ENABLED(CONFIG_TYPEC_DP_ALTMODE)
+int dp_altmode_probe(struct typec_altmode *alt);
+void dp_altmode_remove(struct typec_altmode *alt);
+#else
+int dp_altmode_probe(struct typec_altmode *alt) { return -ENOTSUPP; }
+void dp_altmode_remove(struct typec_altmode *alt) { }
+#endif /* CONFIG_TYPEC_DP_ALTMODE */
-- 
2.17.1



[PATCH 0/2] Add VirtualLink display altmode support

2019-04-10 Thread Ajay Gupta
Hi Heikki,

Please help review these two changes which adds support for
VirtualLink display altmode devices using NVIDIA GPU.

You had shared the first patch during our offline discussion.
The second patch adds NVIDIA display altmode driver.

This set is created against latest Linus's kernel and patches
at [1] forwarded to Greg from you.

[1] https://marc.info/?l=linux-usb&m=155488414908414&w=2 

Thanks
Ajay

Ajay Gupta (1):
  usb: typec: Add driver for NVIDIA Alt Modes

Heikki Krogerus (1):
  usb: typec: displayport: Export probe and remove functions

 drivers/usb/typec/altmodes/Kconfig   | 10 ++
 drivers/usb/typec/altmodes/Makefile  |  2 ++
 drivers/usb/typec/altmodes/displayport.c | 12 ---
 drivers/usb/typec/altmodes/displayport.h |  8 +
 drivers/usb/typec/altmodes/nvidia.c  | 44 
 drivers/usb/typec/ucsi/ucsi.c|  4 ++-
 include/linux/usb/typec_dp.h |  5 +++
 7 files changed, 79 insertions(+), 6 deletions(-)
 create mode 100644 drivers/usb/typec/altmodes/displayport.h
 create mode 100644 drivers/usb/typec/altmodes/nvidia.c

-- 
2.17.1



[PATCH v6 1/2] usb: typec: ucsi: ccg: add get_fw_info function

2019-04-11 Thread Ajay Gupta
Function is to get the details of ccg firmware and device version.
It will be useful in debugging and also during firmware update.

Signed-off-by: Ajay Gupta 
Signed-off-by: Heikki Krogerus 
---
Changes from v5 to v6
- None

 drivers/usb/typec/ucsi/ucsi_ccg.c | 66 ++-
 1 file changed, 64 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
index de8a43bdff68..3884fb41c72e 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -17,15 +17,54 @@
 #include 
 #include "ucsi.h"
 
+enum enum_fw_mode {
+   BOOT,   /* bootloader */
+   FW1,/* FW partition-1 (contains secondary fw) */
+   FW2,/* FW partition-2 (contains primary fw) */
+   FW_INVALID,
+};
+
+struct ccg_dev_info {
+#define CCG_DEVINFO_FWMODE_SHIFT (0)
+#define CCG_DEVINFO_FWMODE_MASK (0x3 << CCG_DEVINFO_FWMODE_SHIFT)
+#define CCG_DEVINFO_PDPORTS_SHIFT (2)
+#define CCG_DEVINFO_PDPORTS_MASK (0x3 << CCG_DEVINFO_PDPORTS_SHIFT)
+   u8 mode;
+   u8 bl_mode;
+   __le16 silicon_id;
+   __le16 bl_last_row;
+} __packed;
+
+struct version_format {
+   __le16 build;
+   u8 patch;
+   u8 ver;
+#define CCG_VERSION_MIN_SHIFT (0)
+#define CCG_VERSION_MIN_MASK (0xf << CCG_VERSION_MIN_SHIFT)
+#define CCG_VERSION_MAJ_SHIFT (4)
+#define CCG_VERSION_MAJ_MASK (0xf << CCG_VERSION_MAJ_SHIFT)
+} __packed;
+
+struct version_info {
+   struct version_format base;
+   struct version_format app;
+};
+
 struct ucsi_ccg {
struct device *dev;
struct ucsi *ucsi;
struct ucsi_ppm ppm;
struct i2c_client *client;
+   struct ccg_dev_info info;
+   /* version info for boot, primary and secondary */
+   struct version_info version[FW2 + 1];
 };
 
-#define CCGX_RAB_INTR_REG  0x06
-#define CCGX_RAB_UCSI_CONTROL  0x39
+#define CCGX_RAB_DEVICE_MODE   0x
+#define CCGX_RAB_INTR_REG  0x0006
+#define CCGX_RAB_READ_ALL_VER  0x0010
+#define CCGX_RAB_READ_FW2_VER  0x0020
+#define CCGX_RAB_UCSI_CONTROL  0x0039
 #define CCGX_RAB_UCSI_CONTROL_STARTBIT(0)
 #define CCGX_RAB_UCSI_CONTROL_STOP BIT(1)
 #define CCGX_RAB_UCSI_DATA_BLOCK(offset)   (0xf000 | ((offset) & 0xff))
@@ -220,6 +259,23 @@ static irqreturn_t ccg_irq_handler(int irq, void *data)
return IRQ_HANDLED;
 }
 
+static int get_fw_info(struct ucsi_ccg *uc)
+{
+   int err;
+
+   err = ccg_read(uc, CCGX_RAB_READ_ALL_VER, (u8 *)(&uc->version),
+  sizeof(uc->version));
+   if (err < 0)
+   return err;
+
+   err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info),
+  sizeof(uc->info));
+   if (err < 0)
+   return err;
+
+   return 0;
+}
+
 static int ucsi_ccg_probe(struct i2c_client *client,
  const struct i2c_device_id *id)
 {
@@ -248,6 +304,12 @@ static int ucsi_ccg_probe(struct i2c_client *client,
return status;
}
 
+   status = get_fw_info(uc);
+   if (status < 0) {
+   dev_err(uc->dev, "get_fw_info failed - %d\n", status);
+   return status;
+   }
+
status = devm_request_threaded_irq(dev, client->irq, NULL,
   ccg_irq_handler,
   IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
-- 
2.17.1



[PATCH v6 0/2] Add support for firmware update on Cypres CCGx

2019-04-11 Thread Ajay Gupta
Hi Heikki

These changes adds support for updating firmware on Cypress CCGx
controller. New version (v6) fixes sparse warning as reported at [1].

I have tested them on NVIDIA GPU card.

Firmware binary is already merged. Details are at [2].

Please help review this set.

Thanks
Ajay

[1] https://marc.info/?l=linux-usb&m=155491396220133&w=2
[2] https://marc.info/?l=linux-usb&m=155006182508289&w=2


Ajay Gupta (2):
  usb: typec: ucsi: ccg: add get_fw_info function
  usb: typec: ucsi: ccg: add firmware flashing support

 drivers/usb/typec/ucsi/ucsi_ccg.c | 887 +-
 1 file changed, 877 insertions(+), 10 deletions(-)

-- 
2.17.1



[PATCH v6 2/2] usb: typec: ucsi: ccg: add firmware flashing support

2019-04-11 Thread Ajay Gupta
CCGx has two copies of the firmware in addition to the bootloader.
If the device is running FW1, FW2 can be updated with the new version.
Dual firmware mode allows the CCG device to stay in a PD contract and
support USB PD and Type-C functionality while a firmware update is in
progress.

First we read the currently flashed firmware version of both
primary and secondary firmware and then compare it with
version of firmware file to determine if flashing is required.

Command framework is added to support sending commands to CCGx
controller. We wait for response after sending the command and then
read the response from RAB_RESPONSE register.

Below commands are supported,
- ENTER_FLASHING
- RESET
- PDPORT_ENABLE
- JUMP_TO_BOOT
- FLASH_ROW_RW
- VALIDATE_FW

Command specific mutex lock is also added to sync between driver
and user threads.

PD port number information is added which is required while sending
PD_PORT_ENABLE command

Signed-off-by: Ajay Gupta 
---
Changes from v5 to v6
- Fixed below sparse warnings
"restricted __le16 degrades to integer"

 drivers/usb/typec/ucsi/ucsi_ccg.c | 831 +-
 1 file changed, 818 insertions(+), 13 deletions(-)

diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
index 3884fb41c72e..a899d4c29125 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -9,6 +9,7 @@
  */
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -24,6 +25,73 @@ enum enum_fw_mode {
FW_INVALID,
 };
 
+#define CCGX_RAB_DEVICE_MODE   0x
+#define CCGX_RAB_INTR_REG  0x0006
+#define  DEV_INT   BIT(0)
+#define  PORT0_INT BIT(1)
+#define  PORT1_INT BIT(2)
+#define  UCSI_READ_INT BIT(7)
+#define CCGX_RAB_JUMP_TO_BOOT  0x0007
+#define  TO_BOOT   'J'
+#define  TO_ALT_FW 'A'
+#define CCGX_RAB_RESET_REQ 0x0008
+#define  RESET_SIG 'R'
+#define  CMD_RESET_I2C 0x0
+#define  CMD_RESET_DEV 0x1
+#define CCGX_RAB_ENTER_FLASHING0x000A
+#define  FLASH_ENTER_SIG   'P'
+#define CCGX_RAB_VALIDATE_FW   0x000B
+#define CCGX_RAB_FLASH_ROW_RW  0x000C
+#define  FLASH_SIG 'F'
+#define  FLASH_RD_CMD  0x0
+#define  FLASH_WR_CMD  0x1
+#define  FLASH_FWCT1_WR_CMD0x2
+#define  FLASH_FWCT2_WR_CMD0x3
+#define  FLASH_FWCT_SIG_WR_CMD 0x4
+#define CCGX_RAB_READ_ALL_VER  0x0010
+#define CCGX_RAB_READ_FW2_VER  0x0020
+#define CCGX_RAB_UCSI_CONTROL  0x0039
+#define CCGX_RAB_UCSI_CONTROL_STARTBIT(0)
+#define CCGX_RAB_UCSI_CONTROL_STOP BIT(1)
+#define CCGX_RAB_UCSI_DATA_BLOCK(offset)   (0xf000 | ((offset) & 0xff))
+#define REG_FLASH_RW_MEM0x0200
+#define DEV_REG_IDXCCGX_RAB_DEVICE_MODE
+#define CCGX_RAB_PDPORT_ENABLE 0x002C
+#define  PDPORT_1  BIT(0)
+#define  PDPORT_2  BIT(1)
+#define CCGX_RAB_RESPONSE  0x007E
+#define  ASYNC_EVENT   BIT(7)
+
+/* CCGx events & async msg codes */
+#define RESET_COMPLETE 0x80
+#define EVENT_INDEXRESET_COMPLETE
+#define PORT_CONNECT_DET   0x84
+#define PORT_DISCONNECT_DET0x85
+#define ROLE_SWAP_COMPELETE0x87
+
+/* ccg firmware */
+#define CYACD_LINE_SIZE 527
+#define CCG4_ROW_SIZE   256
+#define FW1_METADATA_ROW0x1FF
+#define FW2_METADATA_ROW0x1FE
+#define FW_CFG_TABLE_SIG_SIZE  256
+
+static int secondary_fw_min_ver = 41;
+
+enum enum_flash_mode {
+   SECONDARY_BL,   /* update secondary using bootloader */
+   PRIMARY,/* update primary using secondary */
+   SECONDARY,  /* update secondary using primary */
+   FLASH_NOT_NEEDED,   /* update not required */
+   FLASH_INVALID,
+};
+
+static const char * const ccg_fw_names[] = {
+   "ccg_boot.cyacd",
+   "ccg_primary.cyacd",
+   "ccg_secondary.cyacd"
+};
+
 struct ccg_dev_info {
 #define CCG_DEVINFO_FWMODE_SHIFT (0)
 #define CCG_DEVINFO_FWMODE_MASK (0x3 << CCG_DEVINFO_FWMODE_SHIFT)
@@ -50,6 +118,50 @@ struct version_info {
struct version_format app;
 };
 
+struct fw_config_table {
+   u32 identity;
+   u16 table_size;
+   u8 fwct_version;
+   u8 is_key_change;
+   u8 guid[16];
+   struct version_format base;
+   struct version_format ap

RE: [PATCH 2/4] usb: typec: ucsi: ccg: add firmware flashing support

2019-04-11 Thread Ajay Gupta
Hi Heikki,

> -Original Message-
> From: Heikki Krogerus 
> Sent: Thursday, April 11, 2019 12:40 AM
> To: Ajay Gupta 
> Cc: kbuild test robot ; kbuild-...@01.org; Greg Kroah-Hartman
> ; linux-usb@vger.kernel.org
> Subject: Re: [PATCH 2/4] usb: typec: ucsi: ccg: add firmware flashing support
> 
> Hi Ajay,
> 
> On Thu, Apr 11, 2019 at 12:31:45AM +0800, kbuild test robot wrote:
> > Hi Heikki,
> >
> > I love your patch! Perhaps something to improve:
> >
> > [auto build test WARNING on usb/usb-testing] [also build test WARNING
> > on v5.1-rc4 next-20190410] [if your patch is applied to the wrong git
> > tree, please drop us a note to help improve the system]
> >
> > url:https://github.com/0day-ci/linux/commits/Heikki-Krogerus/usb-typec-
> ucsi-Remaining-changes-for-v5-2/20190410-221455
> > base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-
> testing
> > reproduce:
> > # apt-get install sparse
> > make ARCH=x86_64 allmodconfig
> > make C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__'
> >
> >
> > sparse warnings: (new ones prefixed by >>)
> >
> >drivers/usb/typec/ucsi/ucsi_ccg.c:212:24: sparse: expression using
> sizeof(void)
> >drivers/usb/typec/ucsi/ucsi_ccg.c:212:24: sparse: expression using
> > sizeof(void)
> > >> drivers/usb/typec/ucsi/ucsi_ccg.c:690:16: sparse: restricted __le16
> > >> degrades to integer
> >drivers/usb/typec/ucsi/ucsi_ccg.c:698:24: sparse: restricted __le16 
> > degrades
> to integer
> >drivers/usb/typec/ucsi/ucsi_ccg.c:735:26: sparse: restricted __le16 
> > degrades
> to integer
> >drivers/usb/typec/ucsi/ucsi_ccg.c:737:33: sparse: restricted __le16 
> > degrades
> to integer
> >drivers/usb/typec/ucsi/ucsi_ccg.c:777:37: sparse: restricted __le16
> > degrades to integer
> >
> > vim +690 drivers/usb/typec/ucsi/ucsi_ccg.c
> >
> >680
> >681  static bool ccg_check_vendor_version(struct ucsi_ccg *uc,
> >682   struct version_format *app,
> >683   struct fw_config_table 
> > *fw_cfg)
> >684  {
> >685  struct device *dev = uc->dev;
> >686
> >687  /* Check if the fw build is for supported vendors.
> >688   * Add all supported vendors here.
> >689   */
> >  > 690  if (app->build != (('n' << 8) | 'v')) {
> 
> How about a macro for these?
> 
> #define CCG_VERSION_BUILD   (__le16)(...)
Sure, I have fixed them and posted version-6 of patches at
https://marc.info/?l=linux-usb&m=155501300619846&w=2 

Please help review.

Thanks
> nvpublic
> 
> >691  dev_info(dev, "current fw is not from supported
> vendor\n");
> >692  return false;
> >693  }
> >694
> >695  /* Check if the new fw build is for supported vendors
> >696   * Add all supported vendors here.
> >697   */
> >698  if (fw_cfg->app.build != (('n' << 8) | 'v')) {
> >699  dev_info(dev, "new fw is not from supported
> vendor\n");
> >700  return false;
> >701  }
> >702  return true;
> >703  }
> >704
> 
> thanks,
> 
> --
> heikki


RE: [PATCH v6 2/2] usb: typec: ucsi: ccg: add firmware flashing support

2019-04-12 Thread Ajay Gupta
Hi Heikki,

> -Original Message-
> From: linux-usb-ow...@vger.kernel.org  On
> Behalf Of Heikki Krogerus
> Sent: Friday, April 12, 2019 8:02 AM
> To: Ajay Gupta 
> Cc: linux-usb@vger.kernel.org; Ajay Gupta 
> Subject: Re: [PATCH v6 2/2] usb: typec: ucsi: ccg: add firmware flashing 
> support
> 
> Hi Ajay,
> 
> On Thu, Apr 11, 2019 at 01:03:10PM -0700, Ajay Gupta wrote:
> > +#define CCG_FW_VERSION_NVIDIA(b)   (le16_to_cpu(b) != (('n' << 8) |
> 'v'))
> 
> Does that remove the sparce warning?
Yes. I tested it with steps given at 
https://marc.info/?l=linux-usb&m=155491396220133&w=2 

> Now that I see that this version is specific to NVIDIA,
> I think we are going to
> want to get this detail from a device property. I'll prepare an example for 
> you
> right now so you can see how it can be done.
This version supports NVIDIA specific FW signature which is used to test it. 
See 'n' and 'v' letters in it. Other vendors will have their own signature and 
can just add macros to handle it. 

There is also a comment " Add all supported vendors here " for this in function 
ccg_check_vendor_version()
 
Thanks
> nvpublic
> > +static bool ccg_check_vendor_version(struct ucsi_ccg *uc,
> > +struct version_format *app,
> > +struct fw_config_table *fw_cfg) {
> > +   struct device *dev = uc->dev;
> > +
> > +   /* Check if the fw build is for supported vendors.
> > +* Add all supported vendors here.
> > +*/
> > +   if (CCG_FW_VERSION_NVIDIA(app->build)) {
> > +   dev_info(dev, "current fw is not from supported vendor\n");
> > +   return false;
> > +   }
> > +
> > +   /* Check if the new fw build is for supported vendors
> > +* Add all supported vendors here.
> > +*/
> > +   if (CCG_FW_VERSION_NVIDIA(fw_cfg->app.build)) {
> > +   dev_info(dev, "new fw is not from supported vendor\n");
> > +   return false;
> > +   }
> > +   return true;
> > +}
> 
> Br,
> 
> --
> heikki


[PATCH v7 0/3] Add support for firmware update on Cypres CCGx

2019-04-12 Thread Ajay Gupta
Hi Heikki

These changes add support for updating firmware on Cypress CCGx
controller. New version (v7) fixes comments from you by reading fw build
information from device property. 

First patch in same as posted with v6. There is no change in it.

Second patch is from you and adds fw_build device property in i2c-nvidia-gpu
driver. I have updated the commit message, added a comment and also used
'n' and 'v' to be more clear than using hex code. I think it should go with
usb tree since it enables a feature in usb driver.

Third patch "usb: typec: ucsi: ccg: add firmware flashing support" has the
change at [1] (from you) squashed into it. I have updated it to fix two sparse
warning and not fail the driver if fw build info in not provided. Instead
just fail fw flashing only.

I have tested them on NVIDIA GPU card.

Firmware binary is already merged. Details are at [2].

Please help review this set.

Thanks
Ajay

[1] https://marc.info/?l=linux-usb&m=155508466310059&w=2
[2] https://marc.info/?l=linux-usb&m=155006182508289&w=2

Ajay Gupta (2):
  usb: typec: ucsi: ccg: add get_fw_info function
  usb: typec: ucsi: ccg: add firmware flashing support

Heikki Krogerus (1):
  i2c: nvidia-gpu: Supply CCGx driver the fw build info

 drivers/i2c/busses/i2c-nvidia-gpu.c |   7 +
 drivers/usb/typec/ucsi/ucsi_ccg.c   | 895 +++-
 2 files changed, 892 insertions(+), 10 deletions(-)

-- 
2.17.1



[PATCH v7 1/3] usb: typec: ucsi: ccg: add get_fw_info function

2019-04-12 Thread Ajay Gupta
Function is to get the details of ccg firmware and device version.
It will be useful in debugging and also during firmware update.

Signed-off-by: Ajay Gupta 
Signed-off-by: Heikki Krogerus 
---
Changes from v6 to v7
- None

 drivers/usb/typec/ucsi/ucsi_ccg.c | 66 ++-
 1 file changed, 64 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
index de8a43bdff68..3884fb41c72e 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -17,15 +17,54 @@
 #include 
 #include "ucsi.h"
 
+enum enum_fw_mode {
+   BOOT,   /* bootloader */
+   FW1,/* FW partition-1 (contains secondary fw) */
+   FW2,/* FW partition-2 (contains primary fw) */
+   FW_INVALID,
+};
+
+struct ccg_dev_info {
+#define CCG_DEVINFO_FWMODE_SHIFT (0)
+#define CCG_DEVINFO_FWMODE_MASK (0x3 << CCG_DEVINFO_FWMODE_SHIFT)
+#define CCG_DEVINFO_PDPORTS_SHIFT (2)
+#define CCG_DEVINFO_PDPORTS_MASK (0x3 << CCG_DEVINFO_PDPORTS_SHIFT)
+   u8 mode;
+   u8 bl_mode;
+   __le16 silicon_id;
+   __le16 bl_last_row;
+} __packed;
+
+struct version_format {
+   __le16 build;
+   u8 patch;
+   u8 ver;
+#define CCG_VERSION_MIN_SHIFT (0)
+#define CCG_VERSION_MIN_MASK (0xf << CCG_VERSION_MIN_SHIFT)
+#define CCG_VERSION_MAJ_SHIFT (4)
+#define CCG_VERSION_MAJ_MASK (0xf << CCG_VERSION_MAJ_SHIFT)
+} __packed;
+
+struct version_info {
+   struct version_format base;
+   struct version_format app;
+};
+
 struct ucsi_ccg {
struct device *dev;
struct ucsi *ucsi;
struct ucsi_ppm ppm;
struct i2c_client *client;
+   struct ccg_dev_info info;
+   /* version info for boot, primary and secondary */
+   struct version_info version[FW2 + 1];
 };
 
-#define CCGX_RAB_INTR_REG  0x06
-#define CCGX_RAB_UCSI_CONTROL  0x39
+#define CCGX_RAB_DEVICE_MODE   0x
+#define CCGX_RAB_INTR_REG  0x0006
+#define CCGX_RAB_READ_ALL_VER  0x0010
+#define CCGX_RAB_READ_FW2_VER  0x0020
+#define CCGX_RAB_UCSI_CONTROL  0x0039
 #define CCGX_RAB_UCSI_CONTROL_STARTBIT(0)
 #define CCGX_RAB_UCSI_CONTROL_STOP BIT(1)
 #define CCGX_RAB_UCSI_DATA_BLOCK(offset)   (0xf000 | ((offset) & 0xff))
@@ -220,6 +259,23 @@ static irqreturn_t ccg_irq_handler(int irq, void *data)
return IRQ_HANDLED;
 }
 
+static int get_fw_info(struct ucsi_ccg *uc)
+{
+   int err;
+
+   err = ccg_read(uc, CCGX_RAB_READ_ALL_VER, (u8 *)(&uc->version),
+  sizeof(uc->version));
+   if (err < 0)
+   return err;
+
+   err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info),
+  sizeof(uc->info));
+   if (err < 0)
+   return err;
+
+   return 0;
+}
+
 static int ucsi_ccg_probe(struct i2c_client *client,
  const struct i2c_device_id *id)
 {
@@ -248,6 +304,12 @@ static int ucsi_ccg_probe(struct i2c_client *client,
return status;
}
 
+   status = get_fw_info(uc);
+   if (status < 0) {
+   dev_err(uc->dev, "get_fw_info failed - %d\n", status);
+   return status;
+   }
+
status = devm_request_threaded_irq(dev, client->irq, NULL,
   ccg_irq_handler,
   IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
-- 
2.17.1



[PATCH v7 2/3] i2c: nvidia-gpu: Supply CCGx driver the fw build info

2019-04-12 Thread Ajay Gupta
From: Heikki Krogerus 

Adding device property "ccgx,firmware-build" for the CCGx
device, so the CCGx driver knows which firmware binary to
use for a specific vendor.

Signed-off-by: Heikki Krogerus 
Signed-off-by: Ajay Gupta 
---
 drivers/i2c/busses/i2c-nvidia-gpu.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
index 4e67d5ed480e..1c8f708f212b 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -253,6 +253,12 @@ static const struct pci_device_id gpu_i2c_ids[] = {
 };
 MODULE_DEVICE_TABLE(pci, gpu_i2c_ids);
 
+static const struct property_entry ccgx_props[] = {
+   /* Use FW built for NVIDIA (nv) only */
+   PROPERTY_ENTRY_U16("ccgx,firmware-build", ('n' << 8) | 'v'),
+   { }
+};
+
 static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
 {
struct i2c_client *ccgx_client;
@@ -267,6 +273,7 @@ static int gpu_populate_client(struct gpu_i2c_dev *i2cd, 
int irq)
sizeof(i2cd->gpu_ccgx_ucsi->type));
i2cd->gpu_ccgx_ucsi->addr = 0x8;
i2cd->gpu_ccgx_ucsi->irq = irq;
+   i2cd->gpu_ccgx_ucsi->properties = ccgx_props;
ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
if (!ccgx_client)
return -ENODEV;
-- 
2.17.1



[PATCH v7 3/3] usb: typec: ucsi: ccg: add firmware flashing support

2019-04-12 Thread Ajay Gupta
CCGx has two copies of the firmware in addition to the bootloader.
If the device is running FW1, FW2 can be updated with the new version.
Dual firmware mode allows the CCG device to stay in a PD contract and
support USB PD and Type-C functionality while a firmware update is in
progress.

First we read the currently flashed firmware version of both
primary and secondary firmware and then compare it with
version of firmware file to determine if flashing is required.

Command framework is added to support sending commands to CCGx
controller. We wait for response after sending the command and then
read the response from RAB_RESPONSE register.

Below commands are supported,
- ENTER_FLASHING
- RESET
- PDPORT_ENABLE
- JUMP_TO_BOOT
- FLASH_ROW_RW
- VALIDATE_FW

Command specific mutex lock is also added to sync between driver
and user threads.

PD port number information is added which is required while sending
PD_PORT_ENABLE command

Signed-off-by: Ajay Gupta 
---
Changes from v6 -> v7
- Read fw_build from device property
- remove unused level ccg_check_fw_version()

 drivers/usb/typec/ucsi/ucsi_ccg.c | 839 +-
 1 file changed, 826 insertions(+), 13 deletions(-)

diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
index 3884fb41c72e..44cadb5d18d3 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -9,6 +9,7 @@
  */
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -24,6 +25,73 @@ enum enum_fw_mode {
FW_INVALID,
 };
 
+#define CCGX_RAB_DEVICE_MODE   0x
+#define CCGX_RAB_INTR_REG  0x0006
+#define  DEV_INT   BIT(0)
+#define  PORT0_INT BIT(1)
+#define  PORT1_INT BIT(2)
+#define  UCSI_READ_INT BIT(7)
+#define CCGX_RAB_JUMP_TO_BOOT  0x0007
+#define  TO_BOOT   'J'
+#define  TO_ALT_FW 'A'
+#define CCGX_RAB_RESET_REQ 0x0008
+#define  RESET_SIG 'R'
+#define  CMD_RESET_I2C 0x0
+#define  CMD_RESET_DEV 0x1
+#define CCGX_RAB_ENTER_FLASHING0x000A
+#define  FLASH_ENTER_SIG   'P'
+#define CCGX_RAB_VALIDATE_FW   0x000B
+#define CCGX_RAB_FLASH_ROW_RW  0x000C
+#define  FLASH_SIG 'F'
+#define  FLASH_RD_CMD  0x0
+#define  FLASH_WR_CMD  0x1
+#define  FLASH_FWCT1_WR_CMD0x2
+#define  FLASH_FWCT2_WR_CMD0x3
+#define  FLASH_FWCT_SIG_WR_CMD 0x4
+#define CCGX_RAB_READ_ALL_VER  0x0010
+#define CCGX_RAB_READ_FW2_VER  0x0020
+#define CCGX_RAB_UCSI_CONTROL  0x0039
+#define CCGX_RAB_UCSI_CONTROL_STARTBIT(0)
+#define CCGX_RAB_UCSI_CONTROL_STOP BIT(1)
+#define CCGX_RAB_UCSI_DATA_BLOCK(offset)   (0xf000 | ((offset) & 0xff))
+#define REG_FLASH_RW_MEM0x0200
+#define DEV_REG_IDXCCGX_RAB_DEVICE_MODE
+#define CCGX_RAB_PDPORT_ENABLE 0x002C
+#define  PDPORT_1  BIT(0)
+#define  PDPORT_2  BIT(1)
+#define CCGX_RAB_RESPONSE  0x007E
+#define  ASYNC_EVENT   BIT(7)
+
+/* CCGx events & async msg codes */
+#define RESET_COMPLETE 0x80
+#define EVENT_INDEXRESET_COMPLETE
+#define PORT_CONNECT_DET   0x84
+#define PORT_DISCONNECT_DET0x85
+#define ROLE_SWAP_COMPELETE0x87
+
+/* ccg firmware */
+#define CYACD_LINE_SIZE 527
+#define CCG4_ROW_SIZE   256
+#define FW1_METADATA_ROW0x1FF
+#define FW2_METADATA_ROW0x1FE
+#define FW_CFG_TABLE_SIG_SIZE  256
+
+static int secondary_fw_min_ver = 41;
+
+enum enum_flash_mode {
+   SECONDARY_BL,   /* update secondary using bootloader */
+   PRIMARY,/* update primary using secondary */
+   SECONDARY,  /* update secondary using primary */
+   FLASH_NOT_NEEDED,   /* update not required */
+   FLASH_INVALID,
+};
+
+static const char * const ccg_fw_names[] = {
+   "ccg_boot.cyacd",
+   "ccg_primary.cyacd",
+   "ccg_secondary.cyacd"
+};
+
 struct ccg_dev_info {
 #define CCG_DEVINFO_FWMODE_SHIFT (0)
 #define CCG_DEVINFO_FWMODE_MASK (0x3 << CCG_DEVINFO_FWMODE_SHIFT)
@@ -50,6 +118,50 @@ struct version_info {
struct version_format app;
 };
 
+struct fw_config_table {
+   u32 identity;
+   u16 table_size;
+   u8 fwct_version;
+   u8 is_key_change;
+   u8 guid[16];
+   struct version_format base;
+   struct version_for

RE: [PATCH v2 6/7] usb: typec: displayport: Export probe and remove functions

2019-04-15 Thread Ajay Gupta
Hi Heikki,

> -Original Message-
> From: linux-usb-ow...@vger.kernel.org  On
> Behalf Of Heikki Krogerus
> Sent: Monday, April 15, 2019 5:10 AM
> To: Greg Kroah-Hartman 
> Cc: Ajay Gupta ; linux-usb@vger.kernel.org
> Subject: [PATCH v2 6/7] usb: typec: displayport: Export probe and remove
> functions
> 
> From: Ajay Gupta 
> 
> VirtualLink standard extends the DisplayPort Alt Mode by utilizing also the 
> USB 2
> pins on the USB Type-C connector.
> It uses the same messages as DisplayPort, but not the DP SVID. At the time of
> writing, USB IF has not assigned a Standard ID (SID) for VirtualLink, so the
> manufacturers of VirtualLink adapters use their Vendor IDs as the SVID.
> 
> Since the SVID specific communication is exactly the same as with DisplayPort
> alternate mode, there is no need to implement separate driver for VirtualLink.
> We'll handle the current VirtualLink adapters with probe drivers, and once 
> there
> is SVID assigned for it, we add it to the displayport alt mode driver.
> 
> To support probing drivers, exporting the probe and remove functions, and also
> changing the DP_HEADER helper macro to use the SVID of the alternate mode
> device instead of the DisplayPort alt mode SVID.
> 
> Suggested-by: Heikki Krogerus 
> Signed-off-by: Ajay Gupta 
> Signed-off-by: Heikki Krogerus 
> ---
>  drivers/usb/typec/altmodes/displayport.c | 12 +++-
>  1 file changed, 7 insertions(+), 5 deletions(-)
Looks like you missed adding displayport.h file. It is available in original 
patch below,
 https://marc.info/?l=linux-usb&m=155492587224379&w=2 


Thanks
> nvpublic
> diff --git a/drivers/usb/typec/altmodes/displayport.c
> b/drivers/usb/typec/altmodes/displayport.c
> index 1b2afeb1eeb6..4092248a5936 100644
> --- a/drivers/usb/typec/altmodes/displayport.c
> +++ b/drivers/usb/typec/altmodes/displayport.c
> @@ -14,7 +14,7 @@
>  #include 
>  #include 
> 
> -#define DP_HEADER(cmd)   (VDO(USB_TYPEC_DP_SID, 1,
> cmd) | \
> +#define DP_HEADER(_dp, cmd)  (VDO((_dp)->alt->svid, 1, cmd) | \
>VDO_OPOS(USB_TYPEC_DP_MODE))
> 
>  enum {
> @@ -155,7 +155,7 @@ static int dp_altmode_configured(struct dp_altmode
> *dp)
> 
>  static int dp_altmode_configure_vdm(struct dp_altmode *dp, u32 conf)  {
> - u32 header = DP_HEADER(DP_CMD_CONFIGURE);
> + u32 header = DP_HEADER(dp, DP_CMD_CONFIGURE);
>   int ret;
> 
>   ret = typec_altmode_notify(dp->alt, TYPEC_STATE_SAFE, &dp->data);
> @@ -193,7 +193,7 @@ static void dp_altmode_work(struct work_struct *work)
>   dev_err(&dp->alt->dev, "failed to enter mode\n");
>   break;
>   case DP_STATE_UPDATE:
> - header = DP_HEADER(DP_CMD_STATUS_UPDATE);
> + header = DP_HEADER(dp, DP_CMD_STATUS_UPDATE);
>   vdo = 1;
>   ret = typec_altmode_vdm(dp->alt, header, &vdo, 2);
>   if (ret)
> @@ -507,7 +507,7 @@ static const struct attribute_group dp_altmode_group =
> {
>   .attrs = dp_altmode_attrs,
>  };
> 
> -static int dp_altmode_probe(struct typec_altmode *alt)
> +int dp_altmode_probe(struct typec_altmode *alt)
>  {
>   const struct typec_altmode *port = typec_altmode_get_partner(alt);
>   struct dp_altmode *dp;
> @@ -545,14 +545,16 @@ static int dp_altmode_probe(struct typec_altmode
> *alt)
> 
>   return 0;
>  }
> +EXPORT_SYMBOL_GPL(dp_altmode_probe);
> 
> -static void dp_altmode_remove(struct typec_altmode *alt)
> +void dp_altmode_remove(struct typec_altmode *alt)
>  {
>   struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
> 
>   sysfs_remove_group(&alt->dev.kobj, &dp_altmode_group);
>   cancel_work_sync(&dp->work);
>  }
> +EXPORT_SYMBOL_GPL(dp_altmode_remove);
> 
>  static const struct typec_device_id dp_typec_id[] = {
>   { USB_TYPEC_DP_SID, USB_TYPEC_DP_MODE },
> --
> 2.20.1



[PATCH v8 0/3] Add support for firmware update on Cypres CCGx

2019-04-16 Thread Ajay Gupta
Hi Heikki

These changes add support for updating firmware on Cypress CCGx
controller. New version (v8) fixes comments from Greg at [1]. 

I have tested them on NVIDIA GPU card.

Firmware binary is already merged. Details are at [2].

Please help review this set.

Thanks
Ajay

[1] https://marc.info/?l=linux-usb&m=15554931927&w=2
[2] https://marc.info/?l=linux-usb&m=155006182508289&w=2


Ajay Gupta (2):
  usb: typec: ucsi: ccg: add get_fw_info function
  usb: typec: ucsi: ccg: add firmware flashing support

Heikki Krogerus (1):
  i2c: nvidia-gpu: Supply CCGx driver the fw build info

 drivers/i2c/busses/i2c-nvidia-gpu.c |   7 +
 drivers/usb/typec/ucsi/ucsi_ccg.c   | 885 +++-
 2 files changed, 882 insertions(+), 10 deletions(-)

-- 
2.17.1



[PATCH v8 1/3] usb: typec: ucsi: ccg: add get_fw_info function

2019-04-16 Thread Ajay Gupta
From: Ajay Gupta 

Function is to get the details of ccg firmware and device version.
It will be useful in debugging and also during firmware update.

Signed-off-by: Ajay Gupta 
Signed-off-by: Heikki Krogerus 
---
Changes from v7 -> v8
- None

 drivers/usb/typec/ucsi/ucsi_ccg.c | 66 ++-
 1 file changed, 64 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
index de8a43bdff68..3884fb41c72e 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -17,15 +17,54 @@
 #include 
 #include "ucsi.h"
 
+enum enum_fw_mode {
+   BOOT,   /* bootloader */
+   FW1,/* FW partition-1 (contains secondary fw) */
+   FW2,/* FW partition-2 (contains primary fw) */
+   FW_INVALID,
+};
+
+struct ccg_dev_info {
+#define CCG_DEVINFO_FWMODE_SHIFT (0)
+#define CCG_DEVINFO_FWMODE_MASK (0x3 << CCG_DEVINFO_FWMODE_SHIFT)
+#define CCG_DEVINFO_PDPORTS_SHIFT (2)
+#define CCG_DEVINFO_PDPORTS_MASK (0x3 << CCG_DEVINFO_PDPORTS_SHIFT)
+   u8 mode;
+   u8 bl_mode;
+   __le16 silicon_id;
+   __le16 bl_last_row;
+} __packed;
+
+struct version_format {
+   __le16 build;
+   u8 patch;
+   u8 ver;
+#define CCG_VERSION_MIN_SHIFT (0)
+#define CCG_VERSION_MIN_MASK (0xf << CCG_VERSION_MIN_SHIFT)
+#define CCG_VERSION_MAJ_SHIFT (4)
+#define CCG_VERSION_MAJ_MASK (0xf << CCG_VERSION_MAJ_SHIFT)
+} __packed;
+
+struct version_info {
+   struct version_format base;
+   struct version_format app;
+};
+
 struct ucsi_ccg {
struct device *dev;
struct ucsi *ucsi;
struct ucsi_ppm ppm;
struct i2c_client *client;
+   struct ccg_dev_info info;
+   /* version info for boot, primary and secondary */
+   struct version_info version[FW2 + 1];
 };
 
-#define CCGX_RAB_INTR_REG  0x06
-#define CCGX_RAB_UCSI_CONTROL  0x39
+#define CCGX_RAB_DEVICE_MODE   0x
+#define CCGX_RAB_INTR_REG  0x0006
+#define CCGX_RAB_READ_ALL_VER  0x0010
+#define CCGX_RAB_READ_FW2_VER  0x0020
+#define CCGX_RAB_UCSI_CONTROL  0x0039
 #define CCGX_RAB_UCSI_CONTROL_STARTBIT(0)
 #define CCGX_RAB_UCSI_CONTROL_STOP BIT(1)
 #define CCGX_RAB_UCSI_DATA_BLOCK(offset)   (0xf000 | ((offset) & 0xff))
@@ -220,6 +259,23 @@ static irqreturn_t ccg_irq_handler(int irq, void *data)
return IRQ_HANDLED;
 }
 
+static int get_fw_info(struct ucsi_ccg *uc)
+{
+   int err;
+
+   err = ccg_read(uc, CCGX_RAB_READ_ALL_VER, (u8 *)(&uc->version),
+  sizeof(uc->version));
+   if (err < 0)
+   return err;
+
+   err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info),
+  sizeof(uc->info));
+   if (err < 0)
+   return err;
+
+   return 0;
+}
+
 static int ucsi_ccg_probe(struct i2c_client *client,
  const struct i2c_device_id *id)
 {
@@ -248,6 +304,12 @@ static int ucsi_ccg_probe(struct i2c_client *client,
return status;
}
 
+   status = get_fw_info(uc);
+   if (status < 0) {
+   dev_err(uc->dev, "get_fw_info failed - %d\n", status);
+   return status;
+   }
+
status = devm_request_threaded_irq(dev, client->irq, NULL,
   ccg_irq_handler,
   IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
-- 
2.17.1



[PATCH v8 2/3] i2c: nvidia-gpu: Supply CCGx driver the fw build info

2019-04-16 Thread Ajay Gupta
From: Ajay Gupta 

Adding device property "ccgx,firmware-build" for the CCGx
device, so the CCGx driver knows which firmware binary to
use for a specific vendor.

Suggested-by: Heikki Krogerus 
Signed-off-by: Ajay Gupta 
Signed-off-by: Heikki Krogerus 
---
Changes from v7->v8
- None

 drivers/i2c/busses/i2c-nvidia-gpu.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
index 4e67d5ed480e..1c8f708f212b 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -253,6 +253,12 @@ static const struct pci_device_id gpu_i2c_ids[] = {
 };
 MODULE_DEVICE_TABLE(pci, gpu_i2c_ids);
 
+static const struct property_entry ccgx_props[] = {
+   /* Use FW built for NVIDIA (nv) only */
+   PROPERTY_ENTRY_U16("ccgx,firmware-build", ('n' << 8) | 'v'),
+   { }
+};
+
 static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
 {
struct i2c_client *ccgx_client;
@@ -267,6 +273,7 @@ static int gpu_populate_client(struct gpu_i2c_dev *i2cd, 
int irq)
sizeof(i2cd->gpu_ccgx_ucsi->type));
i2cd->gpu_ccgx_ucsi->addr = 0x8;
i2cd->gpu_ccgx_ucsi->irq = irq;
+   i2cd->gpu_ccgx_ucsi->properties = ccgx_props;
ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
if (!ccgx_client)
return -ENODEV;
-- 
2.17.1



[PATCH v8 3/3] usb: typec: ucsi: ccg: add firmware flashing support

2019-04-16 Thread Ajay Gupta
From: Ajay Gupta 

CCGx has two copies of the firmware in addition to the bootloader.
If the device is running FW1, FW2 can be updated with the new version.
Dual firmware mode allows the CCG device to stay in a PD contract and
support USB PD and Type-C functionality while a firmware update is in
progress.

First we read the currently flashed firmware version of both
primary and secondary firmware and then compare it with
version of firmware file to determine if flashing is required.

Command framework is added to support sending commands to CCGx
controller. We wait for response after sending the command and then
read the response from RAB_RESPONSE register.

Below commands are supported,
- ENTER_FLASHING
- RESET
- PDPORT_ENABLE
- JUMP_TO_BOOT
- FLASH_ROW_RW
- VALIDATE_FW

Command specific mutex lock is also added to sync between driver
and user threads.

PD port number information is added which is required while sending
PD_PORT_ENABLE command

Signed-off-by: Ajay Gupta 
Signed-off-by: Heikki Krogerus 
---
Changes from v7->v8
- Fixed comments from Greg by dropping do_flash_show()

 drivers/usb/typec/ucsi/ucsi_ccg.c | 829 +-
 1 file changed, 816 insertions(+), 13 deletions(-)

diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
index 3884fb41c72e..22ae0501eeb5 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -9,6 +9,7 @@
  */
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -24,6 +25,73 @@ enum enum_fw_mode {
FW_INVALID,
 };
 
+#define CCGX_RAB_DEVICE_MODE   0x
+#define CCGX_RAB_INTR_REG  0x0006
+#define  DEV_INT   BIT(0)
+#define  PORT0_INT BIT(1)
+#define  PORT1_INT BIT(2)
+#define  UCSI_READ_INT BIT(7)
+#define CCGX_RAB_JUMP_TO_BOOT  0x0007
+#define  TO_BOOT   'J'
+#define  TO_ALT_FW 'A'
+#define CCGX_RAB_RESET_REQ 0x0008
+#define  RESET_SIG 'R'
+#define  CMD_RESET_I2C 0x0
+#define  CMD_RESET_DEV 0x1
+#define CCGX_RAB_ENTER_FLASHING0x000A
+#define  FLASH_ENTER_SIG   'P'
+#define CCGX_RAB_VALIDATE_FW   0x000B
+#define CCGX_RAB_FLASH_ROW_RW  0x000C
+#define  FLASH_SIG 'F'
+#define  FLASH_RD_CMD  0x0
+#define  FLASH_WR_CMD  0x1
+#define  FLASH_FWCT1_WR_CMD0x2
+#define  FLASH_FWCT2_WR_CMD0x3
+#define  FLASH_FWCT_SIG_WR_CMD 0x4
+#define CCGX_RAB_READ_ALL_VER  0x0010
+#define CCGX_RAB_READ_FW2_VER  0x0020
+#define CCGX_RAB_UCSI_CONTROL  0x0039
+#define CCGX_RAB_UCSI_CONTROL_STARTBIT(0)
+#define CCGX_RAB_UCSI_CONTROL_STOP BIT(1)
+#define CCGX_RAB_UCSI_DATA_BLOCK(offset)   (0xf000 | ((offset) & 0xff))
+#define REG_FLASH_RW_MEM0x0200
+#define DEV_REG_IDXCCGX_RAB_DEVICE_MODE
+#define CCGX_RAB_PDPORT_ENABLE 0x002C
+#define  PDPORT_1  BIT(0)
+#define  PDPORT_2  BIT(1)
+#define CCGX_RAB_RESPONSE  0x007E
+#define  ASYNC_EVENT   BIT(7)
+
+/* CCGx events & async msg codes */
+#define RESET_COMPLETE 0x80
+#define EVENT_INDEXRESET_COMPLETE
+#define PORT_CONNECT_DET   0x84
+#define PORT_DISCONNECT_DET0x85
+#define ROLE_SWAP_COMPELETE0x87
+
+/* ccg firmware */
+#define CYACD_LINE_SIZE 527
+#define CCG4_ROW_SIZE   256
+#define FW1_METADATA_ROW0x1FF
+#define FW2_METADATA_ROW0x1FE
+#define FW_CFG_TABLE_SIG_SIZE  256
+
+static int secondary_fw_min_ver = 41;
+
+enum enum_flash_mode {
+   SECONDARY_BL,   /* update secondary using bootloader */
+   PRIMARY,/* update primary using secondary */
+   SECONDARY,  /* update secondary using primary */
+   FLASH_NOT_NEEDED,   /* update not required */
+   FLASH_INVALID,
+};
+
+static const char * const ccg_fw_names[] = {
+   "ccg_boot.cyacd",
+   "ccg_primary.cyacd",
+   "ccg_secondary.cyacd"
+};
+
 struct ccg_dev_info {
 #define CCG_DEVINFO_FWMODE_SHIFT (0)
 #define CCG_DEVINFO_FWMODE_MASK (0x3 << CCG_DEVINFO_FWMODE_SHIFT)
@@ -50,6 +118,50 @@ struct version_info {
struct version_format app;
 };
 
+struct fw_config_table {
+   u32 identity;
+   u16 table_size;
+   u8 fwct_version;
+   u8 is_key_change;
+   u8 guid[16];
+   struct version_format base;
+   st

RE: [PATCH -next] usb: typec: ucsi: ccg: fix missing unlock on error in ccg_cmd_write_flash_row()

2019-04-29 Thread Ajay Gupta
Hi Wei

> -Original Message-
> From: Wei Yongjun 
> Sent: Monday, April 29, 2019 5:27 AM
> To: Heikki Krogerus ; Greg Kroah-Hartman
> ; Ajay Gupta ; Wolfram Sang
> 
> Cc: Wei Yongjun ; linux-usb@vger.kernel.org;
> kernel-janit...@vger.kernel.org
> Subject: [PATCH -next] usb: typec: ucsi: ccg: fix missing unlock on error in
> ccg_cmd_write_flash_row()
> 
> Add the missing unlock before return from function ccg_cmd_write_flash_row()
> in the error handling case.
Thanks for fixing this. The change looks good.

> nvpublic
> 
> Fixes: 5c9ae5a87573 ("usb: typec: ucsi: ccg: add firmware flashing support")
> Signed-off-by: Wei Yongjun 
> ---
>  drivers/usb/typec/ucsi/ucsi_ccg.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c
> b/drivers/usb/typec/ucsi/ucsi_ccg.c
> index 4632b91a04a6..9d46aa9e4e35 100644
> --- a/drivers/usb/typec/ucsi/ucsi_ccg.c
> +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
> @@ -631,6 +631,7 @@ ccg_cmd_write_flash_row(struct ucsi_ccg *uc, u16 row,
>   ret = i2c_master_send(client, buf, CCG4_ROW_SIZE + 2);
>   if (ret != CCG4_ROW_SIZE + 2) {
>   dev_err(uc->dev, "REG_FLASH_RW_MEM write fail %d\n", ret);
> + mutex_unlock(&uc->lock);
>   return ret < 0 ? ret : -EIO;
>   }
> 
> 



[PATCH 2/4] usb: typec: ucsi: ccg: enable runtime pm support

2019-05-17 Thread Ajay Gupta
From: Ajay Gupta 

The change enables runtime pm support to UCSI CCG driver.
ucsi_send_command() is used in resume path and so exported
ucsi_send_command() symbol in ucsi.c for modular build.

Signed-off-by: Ajay Gupta 
---
 drivers/usb/typec/ucsi/ucsi.c |  1 +
 drivers/usb/typec/ucsi/ucsi_ccg.c | 60 +++
 2 files changed, 61 insertions(+)

diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index 7850b851cecd..e9454134d399 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -206,6 +206,7 @@ int ucsi_send_command(struct ucsi *ucsi, struct 
ucsi_control *ctrl,
 
return ret;
 }
+EXPORT_SYMBOL_GPL(ucsi_send_command);
 
 /* -- 
*/
 
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
index 9d46aa9e4e35..cc7094ecda2d 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -14,6 +14,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #include 
 #include "ucsi.h"
@@ -210,6 +212,7 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, 
u32 len)
if (quirks && quirks->max_read_len)
max_read_len = quirks->max_read_len;
 
+   pm_runtime_get_sync(uc->dev);
while (rem_len > 0) {
msgs[1].buf = &data[len - rem_len];
rlen = min_t(u16, rem_len, max_read_len);
@@ -218,12 +221,14 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+   pm_runtime_put_sync(uc->dev);
return status;
}
rab += rlen;
rem_len -= rlen;
}
 
+   pm_runtime_put_sync(uc->dev);
return 0;
 }
 
@@ -249,13 +254,16 @@ static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
msgs[0].len = len + sizeof(rab);
msgs[0].buf = buf;
 
+   pm_runtime_get_sync(uc->dev);
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+   pm_runtime_put_sync(uc->dev);
kfree(buf);
return status;
}
 
+   pm_runtime_put_sync(uc->dev);
kfree(buf);
return 0;
 }
@@ -1134,6 +1142,10 @@ static int ucsi_ccg_probe(struct i2c_client *client,
if (status)
dev_err(uc->dev, "cannot create sysfs group: %d\n", status);
 
+   pm_runtime_set_active(uc->dev);
+   pm_runtime_enable(uc->dev);
+   pm_runtime_idle(uc->dev);
+
return 0;
 }
 
@@ -1143,6 +1155,7 @@ static int ucsi_ccg_remove(struct i2c_client *client)
 
cancel_work_sync(&uc->work);
ucsi_unregister_ppm(uc->ucsi);
+   pm_runtime_disable(uc->dev);
free_irq(uc->irq, uc);
sysfs_remove_group(&uc->dev->kobj, &ucsi_ccg_attr_group);
 
@@ -1155,9 +1168,56 @@ static const struct i2c_device_id ucsi_ccg_device_id[] = 
{
 };
 MODULE_DEVICE_TABLE(i2c, ucsi_ccg_device_id);
 
+static int ucsi_ccg_suspend(struct device *dev)
+{
+   return 0;
+}
+
+static int ucsi_ccg_resume(struct device *dev)
+{
+   struct i2c_client *client = to_i2c_client(dev);
+   struct ucsi_ccg *uc = i2c_get_clientdata(client);
+   struct ucsi *ucsi = uc->ucsi;
+   struct ucsi_control c;
+   int ret;
+
+   /* restore UCSI notification enable mask */
+   UCSI_CMD_SET_NTFY_ENABLE(c, UCSI_ENABLE_NTFY_ALL);
+   ret = ucsi_send_command(ucsi, &c, NULL, 0);
+   if (ret < 0) {
+   dev_err(uc->dev, "%s: failed to set notification enable - %d\n",
+   __func__, ret);
+   }
+   return 0;
+}
+
+static int ucsi_ccg_runtime_suspend(struct device *dev)
+{
+   return 0;
+}
+
+static int ucsi_ccg_runtime_resume(struct device *dev)
+{
+   return 0;
+}
+
+static int ucsi_ccg_runtime_idle(struct device *dev)
+{
+   return 0;
+}
+
+static const struct dev_pm_ops ucsi_ccg_pm = {
+   .suspend = ucsi_ccg_suspend,
+   .resume = ucsi_ccg_resume,
+   .runtime_suspend = ucsi_ccg_runtime_suspend,
+   .runtime_resume = ucsi_ccg_runtime_resume,
+   .runtime_idle = ucsi_ccg_runtime_idle,
+};
+
 static struct i2c_driver ucsi_ccg_driver = {
.driver = {
.name = "ucsi_ccg",
+   .pm = &ucsi_ccg_pm,
},
.probe = ucsi_ccg_probe,
.remove = ucsi_ccg_remove,
-- 
2.17.1



[PATCH 1/4] i2c: nvidia-gpu: add runtime pm support

2019-05-17 Thread Ajay Gupta
From: Ajay Gupta 

Enable runtime pm support with autosuspend delay of three second.
This is to make sure I2C client device Cypress CCGx has completed
all transaction.

Signed-off-by: Ajay Gupta 
---
 drivers/i2c/busses/i2c-nvidia-gpu.c | 24 +---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
index 1c8f708f212b..9d347583f8dc 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -175,6 +175,7 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
 * The controller supports maximum 4 byte read due to known
 * limitation of sending STOP after every read.
 */
+   pm_runtime_get_sync(i2cd->dev);
for (i = 0; i < num; i++) {
if (msgs[i].flags & I2C_M_RD) {
/* program client address before starting read */
@@ -189,7 +190,7 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
status = gpu_i2c_start(i2cd);
if (status < 0) {
if (i == 0)
-   return status;
+   goto exit;
goto stop;
}
 
@@ -206,13 +207,18 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
}
status = gpu_i2c_stop(i2cd);
if (status < 0)
-   return status;
+   goto exit;
 
+   pm_runtime_mark_last_busy(i2cd->dev);
+   pm_runtime_put_autosuspend(i2cd->dev);
return i;
 stop:
status2 = gpu_i2c_stop(i2cd);
if (status2 < 0)
dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
+exit:
+   pm_runtime_mark_last_busy(i2cd->dev);
+   pm_runtime_put_autosuspend(i2cd->dev);
return status;
 }
 
@@ -332,6 +338,11 @@ static int gpu_i2c_probe(struct pci_dev *pdev, const 
struct pci_device_id *id)
goto del_adapter;
}
 
+   pm_runtime_set_autosuspend_delay(&pdev->dev, 3000);
+   pm_runtime_use_autosuspend(&pdev->dev);
+   pm_runtime_put_autosuspend(&pdev->dev);
+   pm_runtime_allow(&pdev->dev);
+
return 0;
 
 del_adapter:
@@ -345,10 +356,16 @@ static void gpu_i2c_remove(struct pci_dev *pdev)
 {
struct gpu_i2c_dev *i2cd = dev_get_drvdata(&pdev->dev);
 
+   pm_runtime_get_noresume(i2cd->dev);
i2c_del_adapter(&i2cd->adapter);
pci_free_irq_vectors(pdev);
 }
 
+static int gpu_i2c_suspend(struct device *dev)
+{
+   return 0;
+}
+
 static __maybe_unused int gpu_i2c_resume(struct device *dev)
 {
struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
@@ -357,7 +374,8 @@ static __maybe_unused int gpu_i2c_resume(struct device *dev)
return 0;
 }
 
-static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, NULL, gpu_i2c_resume, NULL);
+static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, gpu_i2c_suspend, gpu_i2c_resume,
+   NULL);
 
 static struct pci_driver gpu_i2c_driver = {
.name   = "nvidia-gpu",
-- 
2.17.1



[PATCH 4/4] usb: typec: ucsi: ccg: add runtime pm workaround

2019-05-17 Thread Ajay Gupta
From: Ajay Gupta 

Cypress USB Type-C CCGx controller firmware verson 3.1.10
(which is being used in many NVIDIA GPU cards) has known issue of
not triggering interrupt when a USB device is hot plugged to runtime
resume the controller. Many of these cards may get latest kernel but
may not get latest fixed firmware so a workaround is required to
check for any connector change event.

The workaround is that i2c bus driver will call pm_request_resume()
to runtime resume ucsi_ccg driver. CCG driver will call the ISR
for any connector change event only if NVIDIA GPU has old
CCG firmware with the known issue.

Signed-off-by: Ajay Gupta 
---
 drivers/usb/typec/ucsi/ucsi_ccg.c | 78 +--
 1 file changed, 74 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
index cc7094ecda2d..3457e112fdbc 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -109,6 +109,8 @@ struct version_format {
__le16 build;
u8 patch;
u8 ver;
+#define CCG_VERSION_PATCH(x) ((x) << 16)
+#define CCG_VERSION(x) ((x) << 24)
 #define CCG_VERSION_MIN_SHIFT (0)
 #define CCG_VERSION_MIN_MASK (0xf << CCG_VERSION_MIN_SHIFT)
 #define CCG_VERSION_MAJ_SHIFT (4)
@@ -172,6 +174,7 @@ struct ucsi_ccg {
struct ccg_dev_info info;
/* version info for boot, primary and secondary */
struct version_info version[FW2 + 1];
+   u32 fw_version;
/* CCG HPI communication flags */
unsigned long flags;
 #define RESET_PENDING  0
@@ -185,6 +188,10 @@ struct ucsi_ccg {
 
/* fw build with vendor information */
u16 fw_build;
+   bool run_isr; /* flag to call ISR routine during resume */
+   struct work_struct pm_work;
+   u16 old_fw_build;
+   u32 old_fw_version;
 };
 
 static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
@@ -212,6 +219,17 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
if (quirks && quirks->max_read_len)
max_read_len = quirks->max_read_len;
 
+   if (uc->old_fw_build == uc->fw_build &&
+   uc->fw_version <= uc->old_fw_version) {
+   mutex_lock(&uc->lock);
+   /* do not schedule pm_work to run ISR in
+* ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
+* since we are already in ISR path.
+*/
+   uc->run_isr = false;
+   mutex_unlock(&uc->lock);
+   }
+
pm_runtime_get_sync(uc->dev);
while (rem_len > 0) {
msgs[1].buf = &data[len - rem_len];
@@ -254,6 +272,17 @@ static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
msgs[0].len = len + sizeof(rab);
msgs[0].buf = buf;
 
+   if (uc->old_fw_build == uc->fw_build &&
+   uc->fw_version <= uc->old_fw_version) {
+   mutex_lock(&uc->lock);
+   /* do not schedule pm_work to run ISR in
+* ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
+* since we are already in ISR path.
+*/
+   uc->run_isr = false;
+   mutex_unlock(&uc->lock);
+   }
+
pm_runtime_get_sync(uc->dev);
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
@@ -383,6 +412,13 @@ static irqreturn_t ccg_irq_handler(int irq, void *data)
return IRQ_HANDLED;
 }
 
+static void ccg_pm_workaround_work(struct work_struct *pm_work)
+{
+   struct ucsi_ccg *uc = container_of(pm_work, struct ucsi_ccg, pm_work);
+
+   ucsi_notify(uc->ucsi);
+}
+
 static int get_fw_info(struct ucsi_ccg *uc)
 {
int err;
@@ -392,6 +428,9 @@ static int get_fw_info(struct ucsi_ccg *uc)
if (err < 0)
return err;
 
+   uc->fw_version = CCG_VERSION(uc->version[FW2].app.ver) |
+   CCG_VERSION_PATCH(uc->version[FW2].app.patch);
+
err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info),
   sizeof(uc->info));
if (err < 0)
@@ -740,11 +779,12 @@ static bool ccg_check_fw_version(struct ucsi_ccg *uc, 
const char *fw_name,
}
 
/* compare input version with FWCT version */
-   cur_version = le16_to_cpu(app->build) | app->patch << 16 |
-   app->ver << 24;
+   cur_version = le16_to_cpu(app->build) | CCG_VERSION_PATCH(app->patch) |
+   CCG_VERSION(app->ver);
 
-   new_version = le16_to_cpu(fw_cfg.app.build) | fw_cfg.app.patch << 16 |
-   fw_cfg.app.ver << 24;
+   new_version = le16_to_cpu(fw_cfg.app.build) |
+   CCG_VERSION_PATCH(fw_cfg.app.patch) |
+   

[PATCH 0/4] usb: typec: ucsi: ccg: add runtime pm support

2019-05-17 Thread Ajay Gupta
Hi Heikki

These patches add support for runtime power management for UCSI CCGx driver.
I have tested them with NVIDIA GPU card which has i2c interface to talk to
CCG controller. I have added runtime pm support for the i2c bus driver as well.

First two patches add support for runtime pm in i2c bus driver and UCSI CCGx
driver.

Last two patches add workaround for an old version of ccg firmware
which has known issue of not missing interrupt when a device is connected
to runtime resume the ccg controller. The workaround is needed because
if a GPU card doesn't get new firmware but gets new kernel then also it
should continue to work.

Thanks
Ajay

Ajay Gupta (4):
  i2c: nvidia-gpu: add runtime pm support
  usb: typec: ucsi: ccg: enable runtime pm support
  i2c: nvidia-gpu: resume ccgx i2c client
  usb: typec: ucsi: ccg: add runtime pm workaround

 drivers/i2c/busses/i2c-nvidia-gpu.c |  37 ++--
 drivers/usb/typec/ucsi/ucsi.c   |   1 +
 drivers/usb/typec/ucsi/ucsi_ccg.c   | 138 +++-
 3 files changed, 165 insertions(+), 11 deletions(-)

-- 
2.17.1



[PATCH 3/4] i2c: nvidia-gpu: resume ccgx i2c client

2019-05-17 Thread Ajay Gupta
From: Ajay Gupta 

Cypress USB Type-C CCGx controller firmware (which is being used
in many NVIDIA GPU cards) has known issue of not triggering
interrupt when a USB device is hot plugged to runtime resume the
controller. Many of these cards may get latest kernel but may not
get latest fixed firmware so a workaround to check for any
connector change event.

The workaround is to request runtime resume of i2c client
which is UCSI Cypress CCGx driver. CCG driver will call the ISR
for any connector change event only if NVIDIA GPU has old
CCG firmware with the known issue.

Signed-off-by: Ajay Gupta 
---
 drivers/i2c/busses/i2c-nvidia-gpu.c | 13 +
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
index 9d347583f8dc..2f72135a547b 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -51,6 +51,7 @@ struct gpu_i2c_dev {
void __iomem *regs;
struct i2c_adapter adapter;
struct i2c_board_info *gpu_ccgx_ucsi;
+   struct i2c_client *ccgx_client;
 };
 
 static void gpu_enable_i2c_bus(struct gpu_i2c_dev *i2cd)
@@ -267,8 +268,6 @@ static const struct property_entry ccgx_props[] = {
 
 static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
 {
-   struct i2c_client *ccgx_client;
-
i2cd->gpu_ccgx_ucsi = devm_kzalloc(i2cd->dev,
   sizeof(*i2cd->gpu_ccgx_ucsi),
   GFP_KERNEL);
@@ -280,8 +279,8 @@ static int gpu_populate_client(struct gpu_i2c_dev *i2cd, 
int irq)
i2cd->gpu_ccgx_ucsi->addr = 0x8;
i2cd->gpu_ccgx_ucsi->irq = irq;
i2cd->gpu_ccgx_ucsi->properties = ccgx_props;
-   ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
-   if (!ccgx_client)
+   i2cd->ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
+   if (!i2cd->ccgx_client)
return -ENODEV;
 
return 0;
@@ -371,6 +370,12 @@ static __maybe_unused int gpu_i2c_resume(struct device 
*dev)
struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
 
gpu_enable_i2c_bus(i2cd);
+   /* runtime resume ccgx client so that it can see for any
+* connector change event. Old ccg firmware has known
+* issue of not triggering interrupt when a device is
+* connected to runtime resume the controller.
+*/
+   pm_request_resume(&i2cd->ccgx_client->dev);
return 0;
 }
 
-- 
2.17.1



RE: [PATCH 1/4] i2c: nvidia-gpu: add runtime pm support

2019-05-20 Thread Ajay Gupta
Hi Wolfram,

> -Original Message-
> From: Wolfram Sang 
> Sent: Sunday, May 19, 2019 7:47 AM
> To: Ajay Gupta 
> Cc: heikki.kroge...@linux.intel.com; linux-usb@vger.kernel.org; linux-
> i...@vger.kernel.org; Ajay Gupta 
> Subject: Re: [PATCH 1/4] i2c: nvidia-gpu: add runtime pm support
> 
> > diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c
> > b/drivers/i2c/busses/i2c-nvidia-gpu.c
> > index 1c8f708f212b..9d347583f8dc 100644
> > --- a/drivers/i2c/busses/i2c-nvidia-gpu.c
> > +++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
> > @@ -175,6 +175,7 @@ static int gpu_i2c_master_xfer(struct i2c_adapter
> *adap,
> >  * The controller supports maximum 4 byte read due to known
> >  * limitation of sending STOP after every read.
> >  */
> > +   pm_runtime_get_sync(i2cd->dev);
> > for (i = 0; i < num; i++) {
> > if (msgs[i].flags & I2C_M_RD) {
> > /* program client address before starting read */ @@ -
> 189,7 +190,7
> > @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
> > status = gpu_i2c_start(i2cd);
> > if (status < 0) {
> > if (i == 0)
> > -   return status;
> > +   goto exit;
> > goto stop;
> 
> Hmm, goto here, goto there... OK, the code didn't have a good flow even before
> this patch.
[...]
> 
> > }
> >
> > @@ -206,13 +207,18 @@ static int gpu_i2c_master_xfer(struct i2c_adapter
> *adap,
> > }
> > status = gpu_i2c_stop(i2cd);
> > if (status < 0)
> > -   return status;
> > +   goto exit;
> >
> > +   pm_runtime_mark_last_busy(i2cd->dev);
> > +   pm_runtime_put_autosuspend(i2cd->dev);
> > return i;
> >  stop:
> > status2 = gpu_i2c_stop(i2cd);
> > if (status2 < 0)
> > dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
> > +exit:
> > +   pm_runtime_mark_last_busy(i2cd->dev);
> > +   pm_runtime_put_autosuspend(i2cd->dev);
> > return status;
> >  }
> 
> I am not nacking this, yet the use of goto here seems too much for my taste. 
> If
> you could try refactoring the whole code (dunno, maybe using a flag when to
> use stop?), I'd appreciate this.
Ok, I will add a local variable to make it more readable.

Thanks
Ajay
> nvpublic




RE: [PATCH 3/4] i2c: nvidia-gpu: resume ccgx i2c client

2019-05-20 Thread Ajay Gupta
Hi Wolfram,

> -Original Message-
> From: Wolfram Sang 
> Sent: Sunday, May 19, 2019 7:49 AM
> To: Ajay Gupta 
> Cc: heikki.kroge...@linux.intel.com; linux-usb@vger.kernel.org; linux-
> i...@vger.kernel.org; Ajay Gupta 
> Subject: Re: [PATCH 3/4] i2c: nvidia-gpu: resume ccgx i2c client
> 
> 
> > +   /* runtime resume ccgx client so that it can see for any
> > +* connector change event. Old ccg firmware has known
> > +* issue of not triggering interrupt when a device is
> > +* connected to runtime resume the controller.
> > +*/
> 
> Check coding style for comments.
Sure, will fix.
> 
> BTW how do you suggest this gets upstream? Through the usb-tree? Would be
> fine with me. Are there any dependencies? The cover-letter doesn't mention it.
I would prefer it to go through usb-tree since usb ucsi_ccg driver is the main 
driver
getting runtime pm functionality with the series. I will add this information 
in cover
letter too.

Thanks
Ajay
>nvpublic



[PATCH v2 4/5] i2c: nvidia-gpu: resume ccgx i2c client

2019-05-20 Thread Ajay Gupta
From: Ajay Gupta 

Cypress USB Type-C CCGx controller firmware version 3.1.10
(which is being used in many NVIDIA GPU cards) has known issue of
not triggering interrupt when a USB device is hot plugged to runtime
resume the controller. If any GPU card gets latest kernel with runtime
pm support but does not get latest fixed firmware then also it should
continue to work and therefore a workaround is required to check for
any connector change event

The workaround is to request runtime resume of i2c client
which is UCSI Cypress CCGx driver. CCG driver will call the ISR
for any connector change event only if NVIDIA GPU has old
CCG firmware with the known issue.

Signed-off-by: Ajay Gupta 
---
Changes from v1->v2:
Fixed comment from Wolfram by fixing comment style.

 drivers/i2c/busses/i2c-nvidia-gpu.c | 14 ++
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
index af445590041b..6826740fd0f5 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -51,6 +51,7 @@ struct gpu_i2c_dev {
void __iomem *regs;
struct i2c_adapter adapter;
struct i2c_board_info *gpu_ccgx_ucsi;
+   struct i2c_client *ccgx_client;
 };
 
 static void gpu_enable_i2c_bus(struct gpu_i2c_dev *i2cd)
@@ -271,8 +272,6 @@ static const struct property_entry ccgx_props[] = {
 
 static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
 {
-   struct i2c_client *ccgx_client;
-
i2cd->gpu_ccgx_ucsi = devm_kzalloc(i2cd->dev,
   sizeof(*i2cd->gpu_ccgx_ucsi),
   GFP_KERNEL);
@@ -284,8 +283,8 @@ static int gpu_populate_client(struct gpu_i2c_dev *i2cd, 
int irq)
i2cd->gpu_ccgx_ucsi->addr = 0x8;
i2cd->gpu_ccgx_ucsi->irq = irq;
i2cd->gpu_ccgx_ucsi->properties = ccgx_props;
-   ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
-   if (!ccgx_client)
+   i2cd->ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
+   if (!i2cd->ccgx_client)
return -ENODEV;
 
return 0;
@@ -375,6 +374,13 @@ static __maybe_unused int gpu_i2c_resume(struct device 
*dev)
struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
 
gpu_enable_i2c_bus(i2cd);
+   /*
+* Runtime resume ccgx client so that it can see for any
+* connector change event. Old ccg firmware has known
+* issue of not triggering interrupt when a device is
+* connected to runtime resume the controller.
+*/
+   pm_request_resume(&i2cd->ccgx_client->dev);
return 0;
 }
 
-- 
2.17.1



[PATCH v2 2/5] i2c: nvidia-gpu: add runtime pm support

2019-05-20 Thread Ajay Gupta
From: Ajay Gupta 

Enable runtime pm support with autosuspend delay of three second.
This is to make sure I2C client device Cypress CCGx has completed
all transaction.

Signed-off-by: Ajay Gupta 
---
Changes from v1->v2: None

 drivers/i2c/busses/i2c-nvidia-gpu.c | 19 ++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
index 2d9561ec2320..af445590041b 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -176,6 +176,7 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
 * The controller supports maximum 4 byte read due to known
 * limitation of sending STOP after every read.
 */
+   pm_runtime_get_sync(i2cd->dev);
for (i = 0; i < num; i++) {
if (msgs[i].flags & I2C_M_RD) {
/* program client address before starting read */
@@ -211,6 +212,8 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
goto exit;
}
 
+   pm_runtime_mark_last_busy(i2cd->dev);
+   pm_runtime_put_autosuspend(i2cd->dev);
return i;
 exit:
if (send_stop) {
@@ -218,6 +221,8 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
if (status2 < 0)
dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
}
+   pm_runtime_mark_last_busy(i2cd->dev);
+   pm_runtime_put_autosuspend(i2cd->dev);
return status;
 }
 
@@ -337,6 +342,11 @@ static int gpu_i2c_probe(struct pci_dev *pdev, const 
struct pci_device_id *id)
goto del_adapter;
}
 
+   pm_runtime_set_autosuspend_delay(&pdev->dev, 3000);
+   pm_runtime_use_autosuspend(&pdev->dev);
+   pm_runtime_put_autosuspend(&pdev->dev);
+   pm_runtime_allow(&pdev->dev);
+
return 0;
 
 del_adapter:
@@ -350,10 +360,16 @@ static void gpu_i2c_remove(struct pci_dev *pdev)
 {
struct gpu_i2c_dev *i2cd = dev_get_drvdata(&pdev->dev);
 
+   pm_runtime_get_noresume(i2cd->dev);
i2c_del_adapter(&i2cd->adapter);
pci_free_irq_vectors(pdev);
 }
 
+static int gpu_i2c_suspend(struct device *dev)
+{
+   return 0;
+}
+
 static __maybe_unused int gpu_i2c_resume(struct device *dev)
 {
struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
@@ -362,7 +378,8 @@ static __maybe_unused int gpu_i2c_resume(struct device *dev)
return 0;
 }
 
-static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, NULL, gpu_i2c_resume, NULL);
+static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, gpu_i2c_suspend, gpu_i2c_resume,
+   NULL);
 
 static struct pci_driver gpu_i2c_driver = {
.name   = "nvidia-gpu",
-- 
2.17.1



[PATCH v2 0/5] usb: typec: ucsi: ccg: add runtime pm support

2019-05-20 Thread Ajay Gupta
Hi Heikki and Wolfram

These patches add support for runtime power management for UCSI CCGx driver.
I have tested them with NVIDIA GPU card which has i2c interface to talk to
CCG controller. I have added runtime pm support for the i2c bus driver as well.

First patch refactors master_xfer() of i2c driver fixing comment from Wolfram.
Second and third patch add support for runtime pm in i2c bus driver and UCSI 
CCGx
driver.

Last two patches add workaround for an old version of ccg firmware
which has known issue of missing interrupt when a device is connected
to runtime resume the ccg controller. The workaround is needed because
if a GPU card doesn't get new firmware but gets new kernel then also it
should continue to work. The workaround is to request runtime resume of
i2c client which is UCSI Cypress CCGx driver. CCG driver will call the ISR
for any connector change event only if NVIDIA GPU has old CCG firmware with
the known issue.

All the five patches should go together since ucsi_ccg driver is dependent
on i2c driver for runtime pm wokaround. I would prefer it to go through
usb-tree since usb ucsi_ccg driver is the main driver getting runtime pm
functionality with the series.

Thanks
Ajay


Ajay Gupta (5):
  i2c: nvidia-gpu: refactor master_xfer
  i2c: nvidia-gpu: add runtime pm support
  usb: typec: ucsi: ccg: enable runtime pm support
  i2c: nvidia-gpu: resume ccgx i2c client
  usb: typec: ucsi: ccg: add runtime pm workaround

 drivers/i2c/busses/i2c-nvidia-gpu.c |  60 
 drivers/usb/typec/ucsi/ucsi.c   |   1 +
 drivers/usb/typec/ucsi/ucsi_ccg.c   | 140 +++-
 3 files changed, 181 insertions(+), 20 deletions(-)

-- 
2.17.1



[PATCH v2 5/5] usb: typec: ucsi: ccg: add runtime pm workaround

2019-05-20 Thread Ajay Gupta
From: Ajay Gupta 

Cypress USB Type-C CCGx controller firmware version 3.1.10
(which is being used in many NVIDIA GPU cards) has known issue of
not triggering interrupt when a USB device is hot plugged to runtime
resume the controller. If any GPU card gets latest kernel with runtime
pm support but does not get latest fixed firmware then also it should
continue to work and therefore a workaround is required to check for
any connector change event.

The workaround is that i2c bus driver will call pm_request_resume()
to runtime resume ucsi_ccg driver. CCG driver will call the ISR
for any connector change event for NVIDIA GPU card and only if it has
old CCG firmware with the known issue.

Signed-off-by: Ajay Gupta 
---
Changes from v1->v2:
- Fixed comment style
- Added new macros for NVIDIA old FW builds instead of structure
  variable for them
 drivers/usb/typec/ucsi/ucsi_ccg.c | 80 +--
 1 file changed, 76 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
index cc7094ecda2d..0b9f60861497 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -109,12 +109,21 @@ struct version_format {
__le16 build;
u8 patch;
u8 ver;
+#define CCG_VERSION_PATCH(x) ((x) << 16)
+#define CCG_VERSION(x) ((x) << 24)
 #define CCG_VERSION_MIN_SHIFT (0)
 #define CCG_VERSION_MIN_MASK (0xf << CCG_VERSION_MIN_SHIFT)
 #define CCG_VERSION_MAJ_SHIFT (4)
 #define CCG_VERSION_MAJ_MASK (0xf << CCG_VERSION_MAJ_SHIFT)
 } __packed;
 
+/*
+ * Firmware version 3.1.10 or earlier, built for NVIDIA has known issue
+ * of missing interrupt when a device is connected for runtime resume
+ */
+#define CCG_FW_BUILD_NVIDIA(('n' << 8) | 'v')
+#define CCG_OLD_FW_VERSION (CCG_VERSION(0x31) | CCG_VERSION_PATCH(10))
+
 struct version_info {
struct version_format base;
struct version_format app;
@@ -172,6 +181,7 @@ struct ucsi_ccg {
struct ccg_dev_info info;
/* version info for boot, primary and secondary */
struct version_info version[FW2 + 1];
+   u32 fw_version;
/* CCG HPI communication flags */
unsigned long flags;
 #define RESET_PENDING  0
@@ -185,6 +195,8 @@ struct ucsi_ccg {
 
/* fw build with vendor information */
u16 fw_build;
+   bool run_isr; /* flag to call ISR routine during resume */
+   struct work_struct pm_work;
 };
 
 static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
@@ -212,6 +224,18 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
if (quirks && quirks->max_read_len)
max_read_len = quirks->max_read_len;
 
+   if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
+   uc->fw_version <= CCG_OLD_FW_VERSION) {
+   mutex_lock(&uc->lock);
+   /*
+* Do not schedule pm_work to run ISR in
+* ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
+* since we are already in ISR path.
+*/
+   uc->run_isr = false;
+   mutex_unlock(&uc->lock);
+   }
+
pm_runtime_get_sync(uc->dev);
while (rem_len > 0) {
msgs[1].buf = &data[len - rem_len];
@@ -254,6 +278,18 @@ static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
msgs[0].len = len + sizeof(rab);
msgs[0].buf = buf;
 
+   if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
+   uc->fw_version <= CCG_OLD_FW_VERSION) {
+   mutex_lock(&uc->lock);
+   /*
+* Do not schedule pm_work to run ISR in
+* ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
+* since we are already in ISR path.
+*/
+   uc->run_isr = false;
+   mutex_unlock(&uc->lock);
+   }
+
pm_runtime_get_sync(uc->dev);
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
@@ -383,6 +419,13 @@ static irqreturn_t ccg_irq_handler(int irq, void *data)
return IRQ_HANDLED;
 }
 
+static void ccg_pm_workaround_work(struct work_struct *pm_work)
+{
+   struct ucsi_ccg *uc = container_of(pm_work, struct ucsi_ccg, pm_work);
+
+   ucsi_notify(uc->ucsi);
+}
+
 static int get_fw_info(struct ucsi_ccg *uc)
 {
int err;
@@ -392,6 +435,9 @@ static int get_fw_info(struct ucsi_ccg *uc)
if (err < 0)
return err;
 
+   uc->fw_version = CCG_VERSION(uc->version[FW2].app.ver) |
+   CCG_VERSION_PATCH(uc->version[FW2].app.patch);
+
err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info),
   sizeof(uc->info));
if (err < 0)
@

[PATCH v2 1/5] i2c: nvidia-gpu: refactor master_xfer

2019-05-20 Thread Ajay Gupta
From: Ajay Gupta 

Added a local variable "send_stop" to simplify "goto" statements.

The "send_stop" handles below two case
1) When first i2c start fails and so i2c stop is not sent before
exiting

2) When i2c stop failed after all transfers and we do not need to
send another stop before exiting.

Signed-off-by: Ajay Gupta 
---
 drivers/i2c/busses/i2c-nvidia-gpu.c | 27 ---
 1 file changed, 16 insertions(+), 11 deletions(-)

diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
index 1c8f708f212b..2d9561ec2320 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -169,6 +169,7 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
 {
struct gpu_i2c_dev *i2cd = i2c_get_adapdata(adap);
int status, status2;
+   bool send_stop = true;
int i, j;
 
/*
@@ -182,37 +183,41 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
/* gpu_i2c_read has implicit start */
status = gpu_i2c_read(i2cd, msgs[i].buf, msgs[i].len);
if (status < 0)
-   goto stop;
+   goto exit;
} else {
u8 addr = i2c_8bit_addr_from_msg(msgs + i);
 
status = gpu_i2c_start(i2cd);
if (status < 0) {
if (i == 0)
-   return status;
-   goto stop;
+   send_stop = false;
+   goto exit;
}
 
status = gpu_i2c_write(i2cd, addr);
if (status < 0)
-   goto stop;
+   goto exit;
 
for (j = 0; j < msgs[i].len; j++) {
status = gpu_i2c_write(i2cd, msgs[i].buf[j]);
if (status < 0)
-   goto stop;
+   goto exit;
}
}
}
status = gpu_i2c_stop(i2cd);
-   if (status < 0)
-   return status;
+   if (status < 0) {
+   send_stop = false;
+   goto exit;
+   }
 
return i;
-stop:
-   status2 = gpu_i2c_stop(i2cd);
-   if (status2 < 0)
-   dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
+exit:
+   if (send_stop) {
+   status2 = gpu_i2c_stop(i2cd);
+   if (status2 < 0)
+   dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
+   }
return status;
 }
 
-- 
2.17.1



[PATCH v2 3/5] usb: typec: ucsi: ccg: enable runtime pm support

2019-05-20 Thread Ajay Gupta
From: Ajay Gupta 

The change enables runtime pm support to UCSI CCG driver.
ucsi_send_command() is used in resume path and so exported
ucsi_send_command() symbol in ucsi.c for modular build.

Signed-off-by: Ajay Gupta 
---
Changes from v1->v2 : None

 drivers/usb/typec/ucsi/ucsi.c |  1 +
 drivers/usb/typec/ucsi/ucsi_ccg.c | 60 +++
 2 files changed, 61 insertions(+)

diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index 7850b851cecd..e9454134d399 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -206,6 +206,7 @@ int ucsi_send_command(struct ucsi *ucsi, struct 
ucsi_control *ctrl,
 
return ret;
 }
+EXPORT_SYMBOL_GPL(ucsi_send_command);
 
 /* -- 
*/
 
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
index 9d46aa9e4e35..cc7094ecda2d 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -14,6 +14,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #include 
 #include "ucsi.h"
@@ -210,6 +212,7 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, 
u32 len)
if (quirks && quirks->max_read_len)
max_read_len = quirks->max_read_len;
 
+   pm_runtime_get_sync(uc->dev);
while (rem_len > 0) {
msgs[1].buf = &data[len - rem_len];
rlen = min_t(u16, rem_len, max_read_len);
@@ -218,12 +221,14 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+   pm_runtime_put_sync(uc->dev);
return status;
}
rab += rlen;
rem_len -= rlen;
}
 
+   pm_runtime_put_sync(uc->dev);
return 0;
 }
 
@@ -249,13 +254,16 @@ static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
msgs[0].len = len + sizeof(rab);
msgs[0].buf = buf;
 
+   pm_runtime_get_sync(uc->dev);
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+   pm_runtime_put_sync(uc->dev);
kfree(buf);
return status;
}
 
+   pm_runtime_put_sync(uc->dev);
kfree(buf);
return 0;
 }
@@ -1134,6 +1142,10 @@ static int ucsi_ccg_probe(struct i2c_client *client,
if (status)
dev_err(uc->dev, "cannot create sysfs group: %d\n", status);
 
+   pm_runtime_set_active(uc->dev);
+   pm_runtime_enable(uc->dev);
+   pm_runtime_idle(uc->dev);
+
return 0;
 }
 
@@ -1143,6 +1155,7 @@ static int ucsi_ccg_remove(struct i2c_client *client)
 
cancel_work_sync(&uc->work);
ucsi_unregister_ppm(uc->ucsi);
+   pm_runtime_disable(uc->dev);
free_irq(uc->irq, uc);
sysfs_remove_group(&uc->dev->kobj, &ucsi_ccg_attr_group);
 
@@ -1155,9 +1168,56 @@ static const struct i2c_device_id ucsi_ccg_device_id[] = 
{
 };
 MODULE_DEVICE_TABLE(i2c, ucsi_ccg_device_id);
 
+static int ucsi_ccg_suspend(struct device *dev)
+{
+   return 0;
+}
+
+static int ucsi_ccg_resume(struct device *dev)
+{
+   struct i2c_client *client = to_i2c_client(dev);
+   struct ucsi_ccg *uc = i2c_get_clientdata(client);
+   struct ucsi *ucsi = uc->ucsi;
+   struct ucsi_control c;
+   int ret;
+
+   /* restore UCSI notification enable mask */
+   UCSI_CMD_SET_NTFY_ENABLE(c, UCSI_ENABLE_NTFY_ALL);
+   ret = ucsi_send_command(ucsi, &c, NULL, 0);
+   if (ret < 0) {
+   dev_err(uc->dev, "%s: failed to set notification enable - %d\n",
+   __func__, ret);
+   }
+   return 0;
+}
+
+static int ucsi_ccg_runtime_suspend(struct device *dev)
+{
+   return 0;
+}
+
+static int ucsi_ccg_runtime_resume(struct device *dev)
+{
+   return 0;
+}
+
+static int ucsi_ccg_runtime_idle(struct device *dev)
+{
+   return 0;
+}
+
+static const struct dev_pm_ops ucsi_ccg_pm = {
+   .suspend = ucsi_ccg_suspend,
+   .resume = ucsi_ccg_resume,
+   .runtime_suspend = ucsi_ccg_runtime_suspend,
+   .runtime_resume = ucsi_ccg_runtime_resume,
+   .runtime_idle = ucsi_ccg_runtime_idle,
+};
+
 static struct i2c_driver ucsi_ccg_driver = {
.driver = {
.name = "ucsi_ccg",
+   .pm = &ucsi_ccg_pm,
},
.probe = ucsi_ccg_probe,
.remove = ucsi_ccg_remove,
-- 
2.17.1



RE: [PATCH v2 3/5] usb: typec: ucsi: ccg: enable runtime pm support

2019-05-21 Thread Ajay Gupta
Hi Heikki

> > +static int ucsi_ccg_resume(struct device *dev) {
> > +   struct i2c_client *client = to_i2c_client(dev);
> > +   struct ucsi_ccg *uc = i2c_get_clientdata(client);
> > +   struct ucsi *ucsi = uc->ucsi;
> > +   struct ucsi_control c;
> > +   int ret;
> > +
> > +   /* restore UCSI notification enable mask */
> > +   UCSI_CMD_SET_NTFY_ENABLE(c, UCSI_ENABLE_NTFY_ALL);
> > +   ret = ucsi_send_command(ucsi, &c, NULL, 0);
> > +   if (ret < 0) {
> > +   dev_err(uc->dev, "%s: failed to set notification enable - %d\n",
> > +   __func__, ret);
> > +   }
> > +   return 0;
> > +}
> 
> I would prefer that we did this for all methods in ucsi.c, not just ccgx. 
> Could you
> add resume callback to struct ucsi_ppm, and then call it here.
struct ucsi_ppm currently have .sync() and .cmd() callback which is implemented 
by
ucsi_ccg and ucsi_acpi and invoked by usci.c. 

Is it okay to add a callback in this structure and implement inside ucsi.c and 
invoke
from ucsi_ccg and ucsi_acpi? OR we can just add a function in ucsi.c and export 
it
and use it from ucsi_ccg and ucsi_acpi?

> 
> > +static int ucsi_ccg_runtime_suspend(struct device *dev) {
> > +   return 0;
> > +}
> > +
> > +static int ucsi_ccg_runtime_resume(struct device *dev) {
> > +   return 0;
> > +}
> > +
> > +static int ucsi_ccg_runtime_idle(struct device *dev) {
> > +   return 0;
> > +}

> > Oh yes, and do you really need to supply all of those stubs?
We can drop ucsi_ccg_runtime_idle() but we do need
ucsi_ccg_runtime_suspend() and ucsi_ccg_runtime_resume() for
runtime pm functionality.

Thanks
Ajay
> nvpublic
> > +
> > +static const struct dev_pm_ops ucsi_ccg_pm = {
> > +   .suspend = ucsi_ccg_suspend,
> > +   .resume = ucsi_ccg_resume,
> > +   .runtime_suspend = ucsi_ccg_runtime_suspend,
> > +   .runtime_resume = ucsi_ccg_runtime_resume,
> > +   .runtime_idle = ucsi_ccg_runtime_idle, };
> > +
> >  static struct i2c_driver ucsi_ccg_driver = {
> > .driver = {
> > .name = "ucsi_ccg",
> > +   .pm = &ucsi_ccg_pm,
> > },
> > .probe = ucsi_ccg_probe,
> > .remove = ucsi_ccg_remove,
> 
> thanks,
> 
> --
> heikki


[PATCH v3 1/5] i2c: nvidia-gpu: refactor master_xfer

2019-05-22 Thread Ajay Gupta
From: Ajay Gupta 

Added a local variable "send_stop" to simplify "goto" statements.

The "send_stop" handles below two case
1) When first i2c start fails and so i2c stop is not sent before
exiting

2) When i2c stop failed after all transfers and we do not need to
send another stop before exiting.

Signed-off-by: Ajay Gupta 
---
Changes from v2->v3: None

 drivers/i2c/busses/i2c-nvidia-gpu.c | 27 ---
 1 file changed, 16 insertions(+), 11 deletions(-)

diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
index 1c8f708f212b..2d9561ec2320 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -169,6 +169,7 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
 {
struct gpu_i2c_dev *i2cd = i2c_get_adapdata(adap);
int status, status2;
+   bool send_stop = true;
int i, j;
 
/*
@@ -182,37 +183,41 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
/* gpu_i2c_read has implicit start */
status = gpu_i2c_read(i2cd, msgs[i].buf, msgs[i].len);
if (status < 0)
-   goto stop;
+   goto exit;
} else {
u8 addr = i2c_8bit_addr_from_msg(msgs + i);
 
status = gpu_i2c_start(i2cd);
if (status < 0) {
if (i == 0)
-   return status;
-   goto stop;
+   send_stop = false;
+   goto exit;
}
 
status = gpu_i2c_write(i2cd, addr);
if (status < 0)
-   goto stop;
+   goto exit;
 
for (j = 0; j < msgs[i].len; j++) {
status = gpu_i2c_write(i2cd, msgs[i].buf[j]);
if (status < 0)
-   goto stop;
+   goto exit;
}
}
}
status = gpu_i2c_stop(i2cd);
-   if (status < 0)
-   return status;
+   if (status < 0) {
+   send_stop = false;
+   goto exit;
+   }
 
return i;
-stop:
-   status2 = gpu_i2c_stop(i2cd);
-   if (status2 < 0)
-   dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
+exit:
+   if (send_stop) {
+   status2 = gpu_i2c_stop(i2cd);
+   if (status2 < 0)
+   dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
+   }
return status;
 }
 
-- 
2.17.1



[PATCH v3 4/5] i2c: nvidia-gpu: resume ccgx i2c client

2019-05-22 Thread Ajay Gupta
From: Ajay Gupta 

Cypress USB Type-C CCGx controller firmware version 3.1.10
(which is being used in many NVIDIA GPU cards) has known issue of
not triggering interrupt when a USB device is hot plugged to runtime
resume the controller. If any GPU card gets latest kernel with runtime
pm support but does not get latest fixed firmware then also it should
continue to work and therefore a workaround is required to check for
any connector change event

The workaround is to request runtime resume of i2c client
which is UCSI Cypress CCGx driver. CCG driver will call the ISR
for any connector change event only if NVIDIA GPU has old
CCG firmware with the known issue.

Signed-off-by: Ajay Gupta 
---
Changes from v2->v3: None

 drivers/i2c/busses/i2c-nvidia-gpu.c | 14 ++
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
index 28fee85135ac..957b39c9760f 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -51,6 +51,7 @@ struct gpu_i2c_dev {
void __iomem *regs;
struct i2c_adapter adapter;
struct i2c_board_info *gpu_ccgx_ucsi;
+   struct i2c_client *ccgx_client;
 };
 
 static void gpu_enable_i2c_bus(struct gpu_i2c_dev *i2cd)
@@ -271,8 +272,6 @@ static const struct property_entry ccgx_props[] = {
 
 static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
 {
-   struct i2c_client *ccgx_client;
-
i2cd->gpu_ccgx_ucsi = devm_kzalloc(i2cd->dev,
   sizeof(*i2cd->gpu_ccgx_ucsi),
   GFP_KERNEL);
@@ -284,8 +283,8 @@ static int gpu_populate_client(struct gpu_i2c_dev *i2cd, 
int irq)
i2cd->gpu_ccgx_ucsi->addr = 0x8;
i2cd->gpu_ccgx_ucsi->irq = irq;
i2cd->gpu_ccgx_ucsi->properties = ccgx_props;
-   ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
-   if (!ccgx_client)
+   i2cd->ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
+   if (!i2cd->ccgx_client)
return -ENODEV;
 
return 0;
@@ -375,6 +374,13 @@ static __maybe_unused int gpu_i2c_resume(struct device 
*dev)
struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
 
gpu_enable_i2c_bus(i2cd);
+   /*
+* Runtime resume ccgx client so that it can see for any
+* connector change event. Old ccg firmware has known
+* issue of not triggering interrupt when a device is
+* connected to runtime resume the controller.
+*/
+   pm_request_resume(&i2cd->ccgx_client->dev);
return 0;
 }
 
-- 
2.17.1



[PATCH v3 3/5] usb: typec: ucsi: ccg: enable runtime pm support

2019-05-22 Thread Ajay Gupta
From: Ajay Gupta 

The change enables runtime pm support to UCSI CCG driver.
Added ucsi_resume() function to enable notification after
system reusme. Exported both ucsi_resume() and ucsi_send_command()
symbols in ucsi.c for modular build.

Signed-off-by: Ajay Gupta 
---
Changes from v2->v3 : None
- Fixed comments from Heikki by adding ucsi_resume()
in ucsi.c and used it from ucsi_ccg.c
- Also removed ucsi_ccg_runtime_idle() and
ucsi_ccg_suspend() which were stubs and not needed.
- We still need stub fucntion ucsi_ccg_runtime_suspend
for runtime pm functionality

 drivers/usb/typec/ucsi/ucsi.c | 10 
 drivers/usb/typec/ucsi/ucsi.h |  1 +
 drivers/usb/typec/ucsi/ucsi_ccg.c | 38 +++
 3 files changed, 49 insertions(+)

diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index 7850b851cecd..ba288b964dc8 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -206,7 +206,17 @@ int ucsi_send_command(struct ucsi *ucsi, struct 
ucsi_control *ctrl,
 
return ret;
 }
+EXPORT_SYMBOL_GPL(ucsi_send_command);
 
+int ucsi_resume(struct ucsi *ucsi)
+{
+   struct ucsi_control ctrl;
+
+   /* Restore UCSI notification enable mask after system resume */
+   UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_ALL);
+   return ucsi_send_command(ucsi, &ctrl, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(ucsi_resume);
 /* -- 
*/
 
 void ucsi_altmode_update_active(struct ucsi_connector *con)
diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h
index 1e2981aef629..de87d0b8319d 100644
--- a/drivers/usb/typec/ucsi/ucsi.h
+++ b/drivers/usb/typec/ucsi/ucsi.h
@@ -430,6 +430,7 @@ int ucsi_send_command(struct ucsi *ucsi, struct 
ucsi_control *ctrl,
  void *retval, size_t size);
 
 void ucsi_altmode_update_active(struct ucsi_connector *con);
+int ucsi_resume(struct ucsi *ucsi);
 
 #if IS_ENABLED(CONFIG_TYPEC_DP_ALTMODE)
 struct typec_altmode *
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
index 9d46aa9e4e35..b15bc6c29c46 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -14,6 +14,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #include 
 #include "ucsi.h"
@@ -210,6 +212,7 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, 
u32 len)
if (quirks && quirks->max_read_len)
max_read_len = quirks->max_read_len;
 
+   pm_runtime_get_sync(uc->dev);
while (rem_len > 0) {
msgs[1].buf = &data[len - rem_len];
rlen = min_t(u16, rem_len, max_read_len);
@@ -218,12 +221,14 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+   pm_runtime_put_sync(uc->dev);
return status;
}
rab += rlen;
rem_len -= rlen;
}
 
+   pm_runtime_put_sync(uc->dev);
return 0;
 }
 
@@ -249,13 +254,16 @@ static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
msgs[0].len = len + sizeof(rab);
msgs[0].buf = buf;
 
+   pm_runtime_get_sync(uc->dev);
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+   pm_runtime_put_sync(uc->dev);
kfree(buf);
return status;
}
 
+   pm_runtime_put_sync(uc->dev);
kfree(buf);
return 0;
 }
@@ -1134,6 +1142,10 @@ static int ucsi_ccg_probe(struct i2c_client *client,
if (status)
dev_err(uc->dev, "cannot create sysfs group: %d\n", status);
 
+   pm_runtime_set_active(uc->dev);
+   pm_runtime_enable(uc->dev);
+   pm_runtime_idle(uc->dev);
+
return 0;
 }
 
@@ -1143,6 +1155,7 @@ static int ucsi_ccg_remove(struct i2c_client *client)
 
cancel_work_sync(&uc->work);
ucsi_unregister_ppm(uc->ucsi);
+   pm_runtime_disable(uc->dev);
free_irq(uc->irq, uc);
sysfs_remove_group(&uc->dev->kobj, &ucsi_ccg_attr_group);
 
@@ -1155,9 +1168,34 @@ static const struct i2c_device_id ucsi_ccg_device_id[] = 
{
 };
 MODULE_DEVICE_TABLE(i2c, ucsi_ccg_device_id);
 
+static int ucsi_ccg_resume(struct device *dev)
+{
+   struct i2c_client *client = to_i2c_client(dev);
+   struct ucsi_ccg *uc = i2c_get_clientdata(client);
+
+   return ucsi_resume(uc->ucsi);
+}
+
+static int ucsi_ccg_runtime_

[PATCH v3 0/5] usb: typec: ucsi: ccg: add runtime pm support

2019-05-22 Thread Ajay Gupta
Hi Heikki and Wolfram

These patches add support for runtime power management for UCSI CCGx driver.
I have tested them with NVIDIA GPU card which has i2c interface to talk to
CCG controller. I have added runtime pm support for the i2c bus driver as well.

Third version (v3) of patches fix comments from Heikki on adding common function
in ucsi.c which can be used by both ucsi_ccg and ucsi_acpi.

First patch refactors master_xfer() of i2c driver fixing comment from Wolfram.
Second and third patch add support for runtime pm in i2c bus driver and UCSI 
CCGx
driver.

Last two patches add workaround for an old version of ccg firmware
which has known issue of missing interrupt when a device is connected
to runtime resume the ccg controller. The workaround is needed because
if a GPU card doesn't get new firmware but gets new kernel then also it
should continue to work. The workaround is to request runtime resume of
i2c client which is UCSI Cypress CCGx driver. CCG driver will call the ISR
for any connector change event only if NVIDIA GPU has old CCG firmware with
the known issue.

All the five patches should go together since ucsi_ccg driver is dependent
on i2c driver for runtime pm wokaround. I would prefer it to go through
usb-tree since usb ucsi_ccg driver is the main driver getting runtime pm
functionality with the series.

Thanks
Ajay

Ajay Gupta (5):
  i2c: nvidia-gpu: refactor master_xfer
  i2c: nvidia-gpu: add runtime pm support
  usb: typec: ucsi: ccg: enable runtime pm support
  i2c: nvidia-gpu: resume ccgx i2c client
  usb: typec: ucsi: ccg: add runtime pm workaround

 drivers/i2c/busses/i2c-nvidia-gpu.c |  60 ++
 drivers/usb/typec/ucsi/ucsi.c   |  10 +++
 drivers/usb/typec/ucsi/ucsi.h   |   1 +
 drivers/usb/typec/ucsi/ucsi_ccg.c   | 118 +++-
 4 files changed, 169 insertions(+), 20 deletions(-)

-- 
2.17.1



[PATCH v3 2/5] i2c: nvidia-gpu: add runtime pm support

2019-05-22 Thread Ajay Gupta
From: Ajay Gupta 

Enable runtime pm support with autosuspend delay of three second.
This is to make sure I2C client device Cypress CCGx has completed
all transaction.

Signed-off-by: Ajay Gupta 
---
Changes from v1->v2:
- Added __maybe_unused in gpu_i2c_suspend to avoid
warning when CONFIG_PM is disabled. 

 drivers/i2c/busses/i2c-nvidia-gpu.c | 19 ++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
index 2d9561ec2320..28fee85135ac 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -176,6 +176,7 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
 * The controller supports maximum 4 byte read due to known
 * limitation of sending STOP after every read.
 */
+   pm_runtime_get_sync(i2cd->dev);
for (i = 0; i < num; i++) {
if (msgs[i].flags & I2C_M_RD) {
/* program client address before starting read */
@@ -211,6 +212,8 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
goto exit;
}
 
+   pm_runtime_mark_last_busy(i2cd->dev);
+   pm_runtime_put_autosuspend(i2cd->dev);
return i;
 exit:
if (send_stop) {
@@ -218,6 +221,8 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
if (status2 < 0)
dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
}
+   pm_runtime_mark_last_busy(i2cd->dev);
+   pm_runtime_put_autosuspend(i2cd->dev);
return status;
 }
 
@@ -337,6 +342,11 @@ static int gpu_i2c_probe(struct pci_dev *pdev, const 
struct pci_device_id *id)
goto del_adapter;
}
 
+   pm_runtime_set_autosuspend_delay(&pdev->dev, 3000);
+   pm_runtime_use_autosuspend(&pdev->dev);
+   pm_runtime_put_autosuspend(&pdev->dev);
+   pm_runtime_allow(&pdev->dev);
+
return 0;
 
 del_adapter:
@@ -350,10 +360,16 @@ static void gpu_i2c_remove(struct pci_dev *pdev)
 {
struct gpu_i2c_dev *i2cd = dev_get_drvdata(&pdev->dev);
 
+   pm_runtime_get_noresume(i2cd->dev);
i2c_del_adapter(&i2cd->adapter);
pci_free_irq_vectors(pdev);
 }
 
+static __maybe_unused int gpu_i2c_suspend(struct device *dev)
+{
+   return 0;
+}
+
 static __maybe_unused int gpu_i2c_resume(struct device *dev)
 {
struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
@@ -362,7 +378,8 @@ static __maybe_unused int gpu_i2c_resume(struct device *dev)
return 0;
 }
 
-static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, NULL, gpu_i2c_resume, NULL);
+static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, gpu_i2c_suspend, gpu_i2c_resume,
+   NULL);
 
 static struct pci_driver gpu_i2c_driver = {
.name   = "nvidia-gpu",
-- 
2.17.1



[PATCH v3 5/5] usb: typec: ucsi: ccg: add runtime pm workaround

2019-05-22 Thread Ajay Gupta
From: Ajay Gupta 

Cypress USB Type-C CCGx controller firmware version 3.1.10
(which is being used in many NVIDIA GPU cards) has known issue of
not triggering interrupt when a USB device is hot plugged to runtime
resume the controller. If any GPU card gets latest kernel with runtime
pm support but does not get latest fixed firmware then also it should
continue to work and therefore a workaround is required to check for
any connector change event.

The workaround is that i2c bus driver will call pm_request_resume()
to runtime resume ucsi_ccg driver. CCG driver will call the ISR
for any connector change event for NVIDIA GPU card and only if it has
old CCG firmware with the known issue.

Signed-off-by: Ajay Gupta 
---
Changes from v2->v3: None

 drivers/usb/typec/ucsi/ucsi_ccg.c | 80 +--
 1 file changed, 76 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
index b15bc6c29c46..a5b81c011148 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -109,12 +109,21 @@ struct version_format {
__le16 build;
u8 patch;
u8 ver;
+#define CCG_VERSION_PATCH(x) ((x) << 16)
+#define CCG_VERSION(x) ((x) << 24)
 #define CCG_VERSION_MIN_SHIFT (0)
 #define CCG_VERSION_MIN_MASK (0xf << CCG_VERSION_MIN_SHIFT)
 #define CCG_VERSION_MAJ_SHIFT (4)
 #define CCG_VERSION_MAJ_MASK (0xf << CCG_VERSION_MAJ_SHIFT)
 } __packed;
 
+/*
+ * Firmware version 3.1.10 or earlier, built for NVIDIA has known issue
+ * of missing interrupt when a device is connected for runtime resume
+ */
+#define CCG_FW_BUILD_NVIDIA(('n' << 8) | 'v')
+#define CCG_OLD_FW_VERSION (CCG_VERSION(0x31) | CCG_VERSION_PATCH(10))
+
 struct version_info {
struct version_format base;
struct version_format app;
@@ -172,6 +181,7 @@ struct ucsi_ccg {
struct ccg_dev_info info;
/* version info for boot, primary and secondary */
struct version_info version[FW2 + 1];
+   u32 fw_version;
/* CCG HPI communication flags */
unsigned long flags;
 #define RESET_PENDING  0
@@ -185,6 +195,8 @@ struct ucsi_ccg {
 
/* fw build with vendor information */
u16 fw_build;
+   bool run_isr; /* flag to call ISR routine during resume */
+   struct work_struct pm_work;
 };
 
 static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
@@ -212,6 +224,18 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
if (quirks && quirks->max_read_len)
max_read_len = quirks->max_read_len;
 
+   if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
+   uc->fw_version <= CCG_OLD_FW_VERSION) {
+   mutex_lock(&uc->lock);
+   /*
+* Do not schedule pm_work to run ISR in
+* ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
+* since we are already in ISR path.
+*/
+   uc->run_isr = false;
+   mutex_unlock(&uc->lock);
+   }
+
pm_runtime_get_sync(uc->dev);
while (rem_len > 0) {
msgs[1].buf = &data[len - rem_len];
@@ -254,6 +278,18 @@ static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
msgs[0].len = len + sizeof(rab);
msgs[0].buf = buf;
 
+   if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
+   uc->fw_version <= CCG_OLD_FW_VERSION) {
+   mutex_lock(&uc->lock);
+   /*
+* Do not schedule pm_work to run ISR in
+* ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
+* since we are already in ISR path.
+*/
+   uc->run_isr = false;
+   mutex_unlock(&uc->lock);
+   }
+
pm_runtime_get_sync(uc->dev);
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
@@ -383,6 +419,13 @@ static irqreturn_t ccg_irq_handler(int irq, void *data)
return IRQ_HANDLED;
 }
 
+static void ccg_pm_workaround_work(struct work_struct *pm_work)
+{
+   struct ucsi_ccg *uc = container_of(pm_work, struct ucsi_ccg, pm_work);
+
+   ucsi_notify(uc->ucsi);
+}
+
 static int get_fw_info(struct ucsi_ccg *uc)
 {
int err;
@@ -392,6 +435,9 @@ static int get_fw_info(struct ucsi_ccg *uc)
if (err < 0)
return err;
 
+   uc->fw_version = CCG_VERSION(uc->version[FW2].app.ver) |
+   CCG_VERSION_PATCH(uc->version[FW2].app.patch);
+
err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info),
   sizeof(uc->info));
if (err < 0)
@@ -740,11 +786,12 @@ static bool ccg_check_fw_version(struct ucsi_ccg *uc, 
const char *fw_name,
}
 
/* compa

RE: [PATCH v3 2/5] i2c: nvidia-gpu: add runtime pm support

2019-05-28 Thread Ajay Gupta
Hi Wolfram,

> -Original Message-
> From: linux-usb-ow...@vger.kernel.org 
> On Behalf Of Wolfram Sang
> Sent: Saturday, May 25, 2019 12:57 PM
> To: Ajay Gupta 
> Cc: heikki.kroge...@linux.intel.com; linux-usb@vger.kernel.org; linux-
> i...@vger.kernel.org; Ajay Gupta 
> Subject: Re: [PATCH v3 2/5] i2c: nvidia-gpu: add runtime pm support
> 
> 
> > @@ -211,6 +212,8 @@ static int gpu_i2c_master_xfer(struct i2c_adapter
> *adap,
> > goto exit;
> > }
> >
> > +   pm_runtime_mark_last_busy(i2cd->dev);
> > +   pm_runtime_put_autosuspend(i2cd->dev);
> > return i;
> >  exit:
> > if (send_stop) {
> > @@ -218,6 +221,8 @@ static int gpu_i2c_master_xfer(struct i2c_adapter
> *adap,
> > if (status2 < 0)
> > dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
> > }
> > +   pm_runtime_mark_last_busy(i2cd->dev);
> > +   pm_runtime_put_autosuspend(i2cd->dev);
> 
> Maybe another worthwhile refactorization possible here? The exit code path
> and 'all good' code path look very similar. 
> This can be done incrementally, though. I think for now it is okay.
Thanks for suggestion. Yes , it is possible to refactor a bit further here.
 
> > +static __maybe_unused int gpu_i2c_suspend(struct device *dev) {
> > +   return 0;
> > +}
> 
> Why do we need this?
I2C function of PCI bus remains in D0 (lspci output) without this function. 

Following document also seems to insist on this.
" For this to work, the device's driver has to provide a 
pm->runtime_suspend() callback "

Documentation/power/pci.txt 
"First, a PCI device is put into a low-power state, or suspended, with the help
of pm_schedule_suspend() or pm_runtime_suspend() which for PCI devices call
pci_pm_runtime_suspend() to do the actual job.  For this to work, the device's
driver has to provide a pm->runtime_suspend() callback (see below), which is
run by pci_pm_runtime_suspend() as the first action. If the driver's callback
returns successfully, the device's standard configuration registers are saved,
the device is prepared to generate wakeup signals and, finally, it is put into
the target low-power state."

Thanks
Ajay
> nvpublic



RE: [PATCH v3 2/5] i2c: nvidia-gpu: add runtime pm support

2019-05-31 Thread Ajay Gupta
Hi Wolfram,

> > -Original Message-
> > From: linux-usb-ow...@vger.kernel.org  ow...@vger.kernel.org>
> > On Behalf Of Wolfram Sang
> > Sent: Saturday, May 25, 2019 12:57 PM
> > To: Ajay Gupta 
> > Cc: heikki.kroge...@linux.intel.com; linux-usb@vger.kernel.org; linux-
> > i...@vger.kernel.org; Ajay Gupta 
> > Subject: Re: [PATCH v3 2/5] i2c: nvidia-gpu: add runtime pm support
> >
> >
> > > @@ -211,6 +212,8 @@ static int gpu_i2c_master_xfer(struct i2c_adapter
> > *adap,
> > >   goto exit;
> > >   }
> > >
> > > + pm_runtime_mark_last_busy(i2cd->dev);
> > > + pm_runtime_put_autosuspend(i2cd->dev);
> > >   return i;
> > >  exit:
> > >   if (send_stop) {
> > > @@ -218,6 +221,8 @@ static int gpu_i2c_master_xfer(struct i2c_adapter
> > *adap,
> > >   if (status2 < 0)
> > >   dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
> > >   }
> > > + pm_runtime_mark_last_busy(i2cd->dev);
> > > + pm_runtime_put_autosuspend(i2cd->dev);
> >
> > Maybe another worthwhile refactorization possible here? The exit code
> path
> > and 'all good' code path look very similar.
> > This can be done incrementally, though. I think for now it is okay.
> Thanks for suggestion. Yes , it is possible to refactor a bit further here.
> 
> > > +static __maybe_unused int gpu_i2c_suspend(struct device *dev) {
> > > + return 0;
> > > +}
> >
> > Why do we need this?
> I2C function of PCI bus remains in D0 (lspci output) without this function.

Do you still see any issue with gpu_i2c_suspend()?

Thanks
Ajay
> nvpublic
> 
> Following document also seems to insist on this.
> " For this to work, the device's driver has to provide a
> pm->runtime_suspend() callback "
> 
> Documentation/power/pci.txt
> "First, a PCI device is put into a low-power state, or suspended, with the 
> help
> of pm_schedule_suspend() or pm_runtime_suspend() which for PCI devices
> call
> pci_pm_runtime_suspend() to do the actual job.  For this to work, the
> device's
> driver has to provide a pm->runtime_suspend() callback (see below), which
> is
> run by pci_pm_runtime_suspend() as the first action. If the driver's callback
> returns successfully, the device's standard configuration registers are saved,
> the device is prepared to generate wakeup signals and, finally, it is put into
> the target low-power state."
> 
> Thanks
> Ajay
> > nvpublic



[PATCH v4 0/5] usb: typec: ucsi: ccg: add runtime pm support

2019-06-03 Thread Ajay Gupta
Hi Heikki and Wolfram

These patches add support for runtime power management for UCSI CCGx driver.
I have tested them with NVIDIA GPU card which has i2c interface to talk to
CCG controller. I have added runtime pm support for the i2c bus driver as well.

Third version (v4) of patches fix comments from Wolfram on further refactoring
master_xfer() fucntion in i2c-nvidia-gpuc.c file. Also I have added comment on
why we need a stub gpu_i2c_suspend() for runtime pm to work correctly.

First patch refactors master_xfer() of i2c driver fixing comment from Wolfram.
Second and third patch add support for runtime pm in i2c bus driver and UCSI 
CCGx
driver.

Last two patches add workaround for an old version of ccg firmware
which has known issue of missing interrupt when a device is connected
to runtime resume the ccg controller. The workaround is needed because
if a GPU card doesn't get new firmware but gets new kernel then also it
should continue to work. The workaround is to request runtime resume of
i2c client which is UCSI Cypress CCGx driver. CCG driver will call the ISR
for any connector change event only if NVIDIA GPU has old CCG firmware with
the known issue.

All the five patches should go together since ucsi_ccg driver is dependent
on i2c driver for runtime pm wokaround. I would prefer it to go through
usb-tree since usb ucsi_ccg driver is the main driver getting runtime pm
functionality with the series.

Thanks
Ajay


Ajay Gupta (5):
  i2c: nvidia-gpu: refactor master_xfer
  i2c: nvidia-gpu: add runtime pm support
  usb: typec: ucsi: ccg: enable runtime pm support
  i2c: nvidia-gpu: resume ccgx i2c client
  usb: typec: ucsi: ccg: add runtime pm workaround

 drivers/i2c/busses/i2c-nvidia-gpu.c |  71 +
 drivers/usb/typec/ucsi/ucsi.c   |  10 +++
 drivers/usb/typec/ucsi/ucsi.h   |   1 +
 drivers/usb/typec/ucsi/ucsi_ccg.c   | 118 +++-
 4 files changed, 179 insertions(+), 21 deletions(-)

-- 
2.17.1



[PATCH v4 4/5] i2c: nvidia-gpu: resume ccgx i2c client

2019-06-03 Thread Ajay Gupta
From: Ajay Gupta 

Cypress USB Type-C CCGx controller firmware version 3.1.10
(which is being used in many NVIDIA GPU cards) has known issue of
not triggering interrupt when a USB device is hot plugged to runtime
resume the controller. If any GPU card gets latest kernel with runtime
pm support but does not get latest fixed firmware then also it should
continue to work and therefore a workaround is required to check for
any connector change event

The workaround is to request runtime resume of i2c client
which is UCSI Cypress CCGx driver. CCG driver will call the ISR
for any connector change event only if NVIDIA GPU has old
CCG firmware with the known issue.

Signed-off-by: Ajay Gupta 
---
Changes from v3->v4: None

 drivers/i2c/busses/i2c-nvidia-gpu.c | 14 ++
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
index ad1006e72a03..17a7cdf1dea0 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -51,6 +51,7 @@ struct gpu_i2c_dev {
void __iomem *regs;
struct i2c_adapter adapter;
struct i2c_board_info *gpu_ccgx_ucsi;
+   struct i2c_client *ccgx_client;
 };
 
 static void gpu_enable_i2c_bus(struct gpu_i2c_dev *i2cd)
@@ -270,8 +271,6 @@ static const struct property_entry ccgx_props[] = {
 
 static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
 {
-   struct i2c_client *ccgx_client;
-
i2cd->gpu_ccgx_ucsi = devm_kzalloc(i2cd->dev,
   sizeof(*i2cd->gpu_ccgx_ucsi),
   GFP_KERNEL);
@@ -283,8 +282,8 @@ static int gpu_populate_client(struct gpu_i2c_dev *i2cd, 
int irq)
i2cd->gpu_ccgx_ucsi->addr = 0x8;
i2cd->gpu_ccgx_ucsi->irq = irq;
i2cd->gpu_ccgx_ucsi->properties = ccgx_props;
-   ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
-   if (!ccgx_client)
+   i2cd->ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
+   if (!i2cd->ccgx_client)
return -ENODEV;
 
return 0;
@@ -384,6 +383,13 @@ static __maybe_unused int gpu_i2c_resume(struct device 
*dev)
struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
 
gpu_enable_i2c_bus(i2cd);
+   /*
+* Runtime resume ccgx client so that it can see for any
+* connector change event. Old ccg firmware has known
+* issue of not triggering interrupt when a device is
+* connected to runtime resume the controller.
+*/
+   pm_request_resume(&i2cd->ccgx_client->dev);
return 0;
 }
 
-- 
2.17.1



[PATCH v4 5/5] usb: typec: ucsi: ccg: add runtime pm workaround

2019-06-03 Thread Ajay Gupta
From: Ajay Gupta 

Cypress USB Type-C CCGx controller firmware version 3.1.10
(which is being used in many NVIDIA GPU cards) has known issue of
not triggering interrupt when a USB device is hot plugged to runtime
resume the controller. If any GPU card gets latest kernel with runtime
pm support but does not get latest fixed firmware then also it should
continue to work and therefore a workaround is required to check for
any connector change event.

The workaround is that i2c bus driver will call pm_request_resume()
to runtime resume ucsi_ccg driver. CCG driver will call the ISR
for any connector change event for NVIDIA GPU card and only if it has
old CCG firmware with the known issue.

Signed-off-by: Ajay Gupta 
---
Changes from v3->v4: None

 drivers/usb/typec/ucsi/ucsi_ccg.c | 80 +--
 1 file changed, 76 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
index b15bc6c29c46..a5b81c011148 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -109,12 +109,21 @@ struct version_format {
__le16 build;
u8 patch;
u8 ver;
+#define CCG_VERSION_PATCH(x) ((x) << 16)
+#define CCG_VERSION(x) ((x) << 24)
 #define CCG_VERSION_MIN_SHIFT (0)
 #define CCG_VERSION_MIN_MASK (0xf << CCG_VERSION_MIN_SHIFT)
 #define CCG_VERSION_MAJ_SHIFT (4)
 #define CCG_VERSION_MAJ_MASK (0xf << CCG_VERSION_MAJ_SHIFT)
 } __packed;
 
+/*
+ * Firmware version 3.1.10 or earlier, built for NVIDIA has known issue
+ * of missing interrupt when a device is connected for runtime resume
+ */
+#define CCG_FW_BUILD_NVIDIA(('n' << 8) | 'v')
+#define CCG_OLD_FW_VERSION (CCG_VERSION(0x31) | CCG_VERSION_PATCH(10))
+
 struct version_info {
struct version_format base;
struct version_format app;
@@ -172,6 +181,7 @@ struct ucsi_ccg {
struct ccg_dev_info info;
/* version info for boot, primary and secondary */
struct version_info version[FW2 + 1];
+   u32 fw_version;
/* CCG HPI communication flags */
unsigned long flags;
 #define RESET_PENDING  0
@@ -185,6 +195,8 @@ struct ucsi_ccg {
 
/* fw build with vendor information */
u16 fw_build;
+   bool run_isr; /* flag to call ISR routine during resume */
+   struct work_struct pm_work;
 };
 
 static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
@@ -212,6 +224,18 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
if (quirks && quirks->max_read_len)
max_read_len = quirks->max_read_len;
 
+   if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
+   uc->fw_version <= CCG_OLD_FW_VERSION) {
+   mutex_lock(&uc->lock);
+   /*
+* Do not schedule pm_work to run ISR in
+* ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
+* since we are already in ISR path.
+*/
+   uc->run_isr = false;
+   mutex_unlock(&uc->lock);
+   }
+
pm_runtime_get_sync(uc->dev);
while (rem_len > 0) {
msgs[1].buf = &data[len - rem_len];
@@ -254,6 +278,18 @@ static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
msgs[0].len = len + sizeof(rab);
msgs[0].buf = buf;
 
+   if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
+   uc->fw_version <= CCG_OLD_FW_VERSION) {
+   mutex_lock(&uc->lock);
+   /*
+* Do not schedule pm_work to run ISR in
+* ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
+* since we are already in ISR path.
+*/
+   uc->run_isr = false;
+   mutex_unlock(&uc->lock);
+   }
+
pm_runtime_get_sync(uc->dev);
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
@@ -383,6 +419,13 @@ static irqreturn_t ccg_irq_handler(int irq, void *data)
return IRQ_HANDLED;
 }
 
+static void ccg_pm_workaround_work(struct work_struct *pm_work)
+{
+   struct ucsi_ccg *uc = container_of(pm_work, struct ucsi_ccg, pm_work);
+
+   ucsi_notify(uc->ucsi);
+}
+
 static int get_fw_info(struct ucsi_ccg *uc)
 {
int err;
@@ -392,6 +435,9 @@ static int get_fw_info(struct ucsi_ccg *uc)
if (err < 0)
return err;
 
+   uc->fw_version = CCG_VERSION(uc->version[FW2].app.ver) |
+   CCG_VERSION_PATCH(uc->version[FW2].app.patch);
+
err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info),
   sizeof(uc->info));
if (err < 0)
@@ -740,11 +786,12 @@ static bool ccg_check_fw_version(struct ucsi_ccg *uc, 
const char *fw_name,
}
 
/* compa

[PATCH v4 1/5] i2c: nvidia-gpu: refactor master_xfer

2019-06-03 Thread Ajay Gupta
From: Ajay Gupta 

Added a local variable "send_stop" to simplify "goto" statements.

The "send_stop" handles below two case
1) When first i2c start fails and so i2c stop is not sent before
exiting

2) When i2c stop failed after all transfers and we do not need to
send another stop before exiting.

Signed-off-by: Ajay Gupta 
---
Changes from v3->v4:
- Further refactor master_xfer based on Wolfram's comment.

 drivers/i2c/busses/i2c-nvidia-gpu.c | 30 +
 1 file changed, 18 insertions(+), 12 deletions(-)

diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
index 1c8f708f212b..f1771beb75ea 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -169,6 +169,7 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
 {
struct gpu_i2c_dev *i2cd = i2c_get_adapdata(adap);
int status, status2;
+   bool send_stop = true;
int i, j;
 
/*
@@ -182,37 +183,42 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
/* gpu_i2c_read has implicit start */
status = gpu_i2c_read(i2cd, msgs[i].buf, msgs[i].len);
if (status < 0)
-   goto stop;
+   goto exit;
} else {
u8 addr = i2c_8bit_addr_from_msg(msgs + i);
 
status = gpu_i2c_start(i2cd);
if (status < 0) {
if (i == 0)
-   return status;
-   goto stop;
+   send_stop = false;
+   goto exit;
}
 
status = gpu_i2c_write(i2cd, addr);
if (status < 0)
-   goto stop;
+   goto exit;
 
for (j = 0; j < msgs[i].len; j++) {
status = gpu_i2c_write(i2cd, msgs[i].buf[j]);
if (status < 0)
-   goto stop;
+   goto exit;
}
}
}
status = gpu_i2c_stop(i2cd);
-   if (status < 0)
-   return status;
+   if (status < 0) {
+   send_stop = false;
+   goto exit;
+   }
 
-   return i;
-stop:
-   status2 = gpu_i2c_stop(i2cd);
-   if (status2 < 0)
-   dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
+   send_stop = false;
+   status = i;
+exit:
+   if (send_stop) {
+   status2 = gpu_i2c_stop(i2cd);
+   if (status2 < 0)
+   dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
+   }
return status;
 }
 
-- 
2.17.1



[PATCH v4 2/5] i2c: nvidia-gpu: add runtime pm support

2019-06-03 Thread Ajay Gupta
From: Ajay Gupta 

Enable runtime pm support with autosuspend delay of three second.
This is to make sure I2C client device Cypress CCGx has completed
all transaction.

Signed-off-by: Ajay Gupta 
---
Changes from v3->v4:
- Added comment on why stub gpu_i2c_suspend() is needed for
runtime pm to work correctly.

 drivers/i2c/busses/i2c-nvidia-gpu.c | 27 ++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
index f1771beb75ea..ad1006e72a03 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -176,6 +176,7 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
 * The controller supports maximum 4 byte read due to known
 * limitation of sending STOP after every read.
 */
+   pm_runtime_get_sync(i2cd->dev);
for (i = 0; i < num; i++) {
if (msgs[i].flags & I2C_M_RD) {
/* program client address before starting read */
@@ -219,6 +220,8 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
if (status2 < 0)
dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
}
+   pm_runtime_mark_last_busy(i2cd->dev);
+   pm_runtime_put_autosuspend(i2cd->dev);
return status;
 }
 
@@ -338,6 +341,11 @@ static int gpu_i2c_probe(struct pci_dev *pdev, const 
struct pci_device_id *id)
goto del_adapter;
}
 
+   pm_runtime_set_autosuspend_delay(&pdev->dev, 3000);
+   pm_runtime_use_autosuspend(&pdev->dev);
+   pm_runtime_put_autosuspend(&pdev->dev);
+   pm_runtime_allow(&pdev->dev);
+
return 0;
 
 del_adapter:
@@ -351,10 +359,26 @@ static void gpu_i2c_remove(struct pci_dev *pdev)
 {
struct gpu_i2c_dev *i2cd = dev_get_drvdata(&pdev->dev);
 
+   pm_runtime_get_noresume(i2cd->dev);
i2c_del_adapter(&i2cd->adapter);
pci_free_irq_vectors(pdev);
 }
 
+/*
+ * We need gpu_i2c_suspend() even if it is stub, for runtime pm to work
+ * correctly. Without it, lspci shows runtime pm status as "D0" for the card.
+ * Documentation/power/pci.txt also insists for driver to provide this:
+ * "First, a PCI device is put into a low-power state, or suspended, with the
+ * help of pm_schedule_suspend() or pm_runtime_suspend() which for PCI devices
+ * call pci_pm_runtime_suspend() to do the actual job.  For this to work, the
+ * device's driver has to provide a pm->runtime_suspend() callback (see below),
+ * which is run by pci_pm_runtime_suspend() as the first action."
+ */
+static __maybe_unused int gpu_i2c_suspend(struct device *dev)
+{
+   return 0;
+}
+
 static __maybe_unused int gpu_i2c_resume(struct device *dev)
 {
struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
@@ -363,7 +387,8 @@ static __maybe_unused int gpu_i2c_resume(struct device *dev)
return 0;
 }
 
-static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, NULL, gpu_i2c_resume, NULL);
+static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, gpu_i2c_suspend, gpu_i2c_resume,
+   NULL);
 
 static struct pci_driver gpu_i2c_driver = {
.name   = "nvidia-gpu",
-- 
2.17.1



[PATCH v4 3/5] usb: typec: ucsi: ccg: enable runtime pm support

2019-06-03 Thread Ajay Gupta
From: Ajay Gupta 

The change enables runtime pm support to UCSI CCG driver.
Added ucsi_resume() function to enable notification after
system reusme. Exported both ucsi_resume() and ucsi_send_command()
symbols in ucsi.c for modular build.

Signed-off-by: Ajay Gupta 
---
Changes from v3->v4 : None

 drivers/usb/typec/ucsi/ucsi.c | 10 
 drivers/usb/typec/ucsi/ucsi.h |  1 +
 drivers/usb/typec/ucsi/ucsi_ccg.c | 38 +++
 3 files changed, 49 insertions(+)

diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index 7850b851cecd..ba288b964dc8 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -206,7 +206,17 @@ int ucsi_send_command(struct ucsi *ucsi, struct 
ucsi_control *ctrl,
 
return ret;
 }
+EXPORT_SYMBOL_GPL(ucsi_send_command);
 
+int ucsi_resume(struct ucsi *ucsi)
+{
+   struct ucsi_control ctrl;
+
+   /* Restore UCSI notification enable mask after system resume */
+   UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_ALL);
+   return ucsi_send_command(ucsi, &ctrl, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(ucsi_resume);
 /* -- 
*/
 
 void ucsi_altmode_update_active(struct ucsi_connector *con)
diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h
index 1e2981aef629..de87d0b8319d 100644
--- a/drivers/usb/typec/ucsi/ucsi.h
+++ b/drivers/usb/typec/ucsi/ucsi.h
@@ -430,6 +430,7 @@ int ucsi_send_command(struct ucsi *ucsi, struct 
ucsi_control *ctrl,
  void *retval, size_t size);
 
 void ucsi_altmode_update_active(struct ucsi_connector *con);
+int ucsi_resume(struct ucsi *ucsi);
 
 #if IS_ENABLED(CONFIG_TYPEC_DP_ALTMODE)
 struct typec_altmode *
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
index 9d46aa9e4e35..b15bc6c29c46 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -14,6 +14,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #include 
 #include "ucsi.h"
@@ -210,6 +212,7 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, 
u32 len)
if (quirks && quirks->max_read_len)
max_read_len = quirks->max_read_len;
 
+   pm_runtime_get_sync(uc->dev);
while (rem_len > 0) {
msgs[1].buf = &data[len - rem_len];
rlen = min_t(u16, rem_len, max_read_len);
@@ -218,12 +221,14 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+   pm_runtime_put_sync(uc->dev);
return status;
}
rab += rlen;
rem_len -= rlen;
}
 
+   pm_runtime_put_sync(uc->dev);
return 0;
 }
 
@@ -249,13 +254,16 @@ static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
msgs[0].len = len + sizeof(rab);
msgs[0].buf = buf;
 
+   pm_runtime_get_sync(uc->dev);
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+   pm_runtime_put_sync(uc->dev);
kfree(buf);
return status;
}
 
+   pm_runtime_put_sync(uc->dev);
kfree(buf);
return 0;
 }
@@ -1134,6 +1142,10 @@ static int ucsi_ccg_probe(struct i2c_client *client,
if (status)
dev_err(uc->dev, "cannot create sysfs group: %d\n", status);
 
+   pm_runtime_set_active(uc->dev);
+   pm_runtime_enable(uc->dev);
+   pm_runtime_idle(uc->dev);
+
return 0;
 }
 
@@ -1143,6 +1155,7 @@ static int ucsi_ccg_remove(struct i2c_client *client)
 
cancel_work_sync(&uc->work);
ucsi_unregister_ppm(uc->ucsi);
+   pm_runtime_disable(uc->dev);
free_irq(uc->irq, uc);
sysfs_remove_group(&uc->dev->kobj, &ucsi_ccg_attr_group);
 
@@ -1155,9 +1168,34 @@ static const struct i2c_device_id ucsi_ccg_device_id[] = 
{
 };
 MODULE_DEVICE_TABLE(i2c, ucsi_ccg_device_id);
 
+static int ucsi_ccg_resume(struct device *dev)
+{
+   struct i2c_client *client = to_i2c_client(dev);
+   struct ucsi_ccg *uc = i2c_get_clientdata(client);
+
+   return ucsi_resume(uc->ucsi);
+}
+
+static int ucsi_ccg_runtime_suspend(struct device *dev)
+{
+   return 0;
+}
+
+static int ucsi_ccg_runtime_resume(struct device *dev)
+{
+   return 0;
+}
+
+static const struct dev_pm_ops ucsi_ccg_pm = {
+   .resume = ucsi_ccg_resume,
+   .runtime_suspend = ucsi_ccg_runtime_suspend,
+   .runtime_resume = ucsi_ccg_runtime_r

RE: [PATCH v4 3/5] usb: typec: ucsi: ccg: enable runtime pm support

2019-06-07 Thread Ajay Gupta
Hi Heikki and Wolfram,

> -Original Message-
> From: linux-i2c-ow...@vger.kernel.org 
> On Behalf Of Wolfram Sang
> Sent: Friday, June 7, 2019 1:27 AM
> To: Heikki Krogerus 
> Cc: Ajay Gupta ; linux-usb@vger.kernel.org; linux-
> i...@vger.kernel.org; Ajay Gupta 
> Subject: Re: [PATCH v4 3/5] usb: typec: ucsi: ccg: enable runtime pm support
> 
> On Fri, Jun 07, 2019 at 11:25:10AM +0300, Heikki Krogerus wrote:
> > On Mon, Jun 03, 2019 at 10:05:43AM -0700, Ajay Gupta wrote:
> > > From: Ajay Gupta 
> > >
> > > The change enables runtime pm support to UCSI CCG driver.
> > > Added ucsi_resume() function to enable notification after system
> > > reusme. Exported both ucsi_resume() and ucsi_send_command()
> symbols
> > > in ucsi.c for modular build.
> > >
> > > Signed-off-by: Ajay Gupta 
> >
> > Was the idea that Wolfram picks these? In that case:
> 
> Cover letter says your tree, will check the i2c patches now.
Either tree is fine with me. There are 3 (out of 5)  I2C related patches in the 
set so better
they go through I2C tree.

Thanks
Ajay
> nvpublic



RE: [PATCH v4 1/5] i2c: nvidia-gpu: refactor master_xfer

2019-06-07 Thread Ajay Gupta
Hi Wolfram,

> -Original Message-
> From: Wolfram Sang 
> Sent: Friday, June 7, 2019 1:33 AM
> To: Ajay Gupta 
> Cc: heikki.kroge...@linux.intel.com; linux-usb@vger.kernel.org; linux-
> i...@vger.kernel.org; Ajay Gupta 
> Subject: Re: [PATCH v4 1/5] i2c: nvidia-gpu: refactor master_xfer
> 
> > Changes from v3->v4:
> > - Further refactor master_xfer based on Wolfram's comment.
> 
> Yay, looks even better. One thing to improve, though.
> 
> > status = gpu_i2c_stop(i2cd);
> 
> send_stop = false;

> 
> > -   if (status < 0)
> > -   return status;
> > +   if (status < 0) {
> > +   send_stop = false;
> 
> and skip it here...
> 
> > +   goto exit;
> > +   }
> >
> > -   return i;
> > -stop:
> > -   status2 = gpu_i2c_stop(i2cd);
> > -   if (status2 < 0)
> > -   dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
> > +   send_stop = false;
> 
> ... and here.
Sure, will fix.

Thanks
>nvpublic



RE: [PATCH v4 2/5] i2c: nvidia-gpu: add runtime pm support

2019-06-07 Thread Ajay Gupta
Hi Wolfram,

> -Original Message-
> From: linux-i2c-ow...@vger.kernel.org 
> On Behalf Of Wolfram Sang
> Sent: Friday, June 7, 2019 1:33 AM
> To: Ajay Gupta 
> Cc: heikki.kroge...@linux.intel.com; linux-usb@vger.kernel.org; linux-
> i...@vger.kernel.org; Ajay Gupta 
> Subject: Re: [PATCH v4 2/5] i2c: nvidia-gpu: add runtime pm support
> 
> 
> > +   pm_runtime_mark_last_busy(i2cd->dev);
> > +   pm_runtime_put_autosuspend(i2cd->dev);
> 
> Much better to have this only once!
> 
> > +/*
> > + * We need gpu_i2c_suspend() even if it is stub, for runtime pm to
> > +work
> > + * correctly. Without it, lspci shows runtime pm status as "D0" for the
> card.
> > + * Documentation/power/pci.txt also insists for driver to provide this:
> 
> I'd think the comment up to here is enough and the rest can go. However, I
> leave this decision to you.
Sure, will fix it.

Thanks
> nvpublic



[PATCH v5 1/5] i2c: nvidia-gpu: refactor master_xfer

2019-06-07 Thread Ajay Gupta
From: Ajay Gupta 

Added a local variable "send_stop" to simplify "goto" statements.

The "send_stop" handles below two case
1) When first i2c start fails and so i2c stop is not sent before
exiting

2) When i2c stop failed after all transfers and we do not need to
send another stop before exiting.

Signed-off-by: Ajay Gupta 
---
Changes from v4->v5:
- Further refactor master_xfer based on Wolfram's comment.

 drivers/i2c/busses/i2c-nvidia-gpu.c | 28 
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
index 1c8f708f212b..7678a460bf9a 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -169,6 +169,7 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
 {
struct gpu_i2c_dev *i2cd = i2c_get_adapdata(adap);
int status, status2;
+   bool send_stop = true;
int i, j;
 
/*
@@ -182,37 +183,40 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
/* gpu_i2c_read has implicit start */
status = gpu_i2c_read(i2cd, msgs[i].buf, msgs[i].len);
if (status < 0)
-   goto stop;
+   goto exit;
} else {
u8 addr = i2c_8bit_addr_from_msg(msgs + i);
 
status = gpu_i2c_start(i2cd);
if (status < 0) {
if (i == 0)
-   return status;
-   goto stop;
+   send_stop = false;
+   goto exit;
}
 
status = gpu_i2c_write(i2cd, addr);
if (status < 0)
-   goto stop;
+   goto exit;
 
for (j = 0; j < msgs[i].len; j++) {
status = gpu_i2c_write(i2cd, msgs[i].buf[j]);
if (status < 0)
-   goto stop;
+   goto exit;
}
}
}
+   send_stop = false;
status = gpu_i2c_stop(i2cd);
if (status < 0)
-   return status;
-
-   return i;
-stop:
-   status2 = gpu_i2c_stop(i2cd);
-   if (status2 < 0)
-   dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
+   goto exit;
+
+   status = i;
+exit:
+   if (send_stop) {
+   status2 = gpu_i2c_stop(i2cd);
+   if (status2 < 0)
+   dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
+   }
return status;
 }
 
-- 
2.17.1



[PATCH v5 0/5] usb: typec: ucsi: ccg: add runtime pm support

2019-06-07 Thread Ajay Gupta
Hi Heikki and Wolfram
The latest set (v5) fix comments from Wolfram on further refactoring
master_xfer() function in i2c-nvidia-gpuc.c file and removing extra comments
in patch 2/5.

Patches can go through either usb or i2c tree but since there are 3 out of 5
patches from i2c so may be better they go through i2c. They all should go
together.

Thanks
Ajay

 v4
These patches add support for runtime power management for UCSI CCGx driver.
I have tested them with NVIDIA GPU card which has i2c interface to talk to
CCG controller. I have added runtime pm support for the i2c bus driver as well.

Fourth version (v4) of patches fix comments from Wolfram on further refactoring
master_xfer() function in i2c-nvidia-gpuc.c file. Also I have added comment on
why we need a stub gpu_i2c_suspend() for runtime pm to work correctly.

First patch refactors master_xfer() of i2c driver fixing comment from Wolfram.
Second and third patch add support for runtime pm in i2c bus driver and UCSI 
CCGx
driver.

Last two patches add workaround for an old version of ccg firmware
which has known issue of missing interrupt when a device is connected
to runtime resume the ccg controller. The workaround is needed because
if a GPU card doesn't get new firmware but gets new kernel then also it
should continue to work. The workaround is to request runtime resume of
i2c client which is UCSI Cypress CCGx driver. CCG driver will call the ISR
for any connector change event only if NVIDIA GPU has old CCG firmware with
the known issue.

All the five patches should go together since ucsi_ccg driver is dependent
on i2c driver for runtime pm wokaround. I would prefer it to go through
usb-tree since usb ucsi_ccg driver is the main driver getting runtime pm
functionality with the series.

Thanks
Ajay


Ajay Gupta (5):
  i2c: nvidia-gpu: refactor master_xfer
  i2c: nvidia-gpu: add runtime pm support
  usb: typec: ucsi: ccg: enable runtime pm support
  i2c: nvidia-gpu: resume ccgx i2c client
  usb: typec: ucsi: ccg: add runtime pm workaround

 drivers/i2c/busses/i2c-nvidia-gpu.c |  64 +++
 drivers/usb/typec/ucsi/ucsi.c   |  10 +++
 drivers/usb/typec/ucsi/ucsi.h   |   1 +
 drivers/usb/typec/ucsi/ucsi_ccg.c   | 118 +++-
 4 files changed, 172 insertions(+), 21 deletions(-)

-- 
2.17.1



[PATCH v5 4/5] i2c: nvidia-gpu: resume ccgx i2c client

2019-06-07 Thread Ajay Gupta
From: Ajay Gupta 

Cypress USB Type-C CCGx controller firmware version 3.1.10
(which is being used in many NVIDIA GPU cards) has known issue of
not triggering interrupt when a USB device is hot plugged to runtime
resume the controller. If any GPU card gets latest kernel with runtime
pm support but does not get latest fixed firmware then also it should
continue to work and therefore a workaround is required to check for
any connector change event

The workaround is to request runtime resume of i2c client
which is UCSI Cypress CCGx driver. CCG driver will call the ISR
for any connector change event only if NVIDIA GPU has old
CCG firmware with the known issue.

Signed-off-by: Ajay Gupta 
---
Changes from v4->v5: None

 drivers/i2c/busses/i2c-nvidia-gpu.c | 14 ++
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
index 364244ffb5bf..cfc76b5de726 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -51,6 +51,7 @@ struct gpu_i2c_dev {
void __iomem *regs;
struct i2c_adapter adapter;
struct i2c_board_info *gpu_ccgx_ucsi;
+   struct i2c_client *ccgx_client;
 };
 
 static void gpu_enable_i2c_bus(struct gpu_i2c_dev *i2cd)
@@ -268,8 +269,6 @@ static const struct property_entry ccgx_props[] = {
 
 static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq)
 {
-   struct i2c_client *ccgx_client;
-
i2cd->gpu_ccgx_ucsi = devm_kzalloc(i2cd->dev,
   sizeof(*i2cd->gpu_ccgx_ucsi),
   GFP_KERNEL);
@@ -281,8 +280,8 @@ static int gpu_populate_client(struct gpu_i2c_dev *i2cd, 
int irq)
i2cd->gpu_ccgx_ucsi->addr = 0x8;
i2cd->gpu_ccgx_ucsi->irq = irq;
i2cd->gpu_ccgx_ucsi->properties = ccgx_props;
-   ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
-   if (!ccgx_client)
+   i2cd->ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi);
+   if (!i2cd->ccgx_client)
return -ENODEV;
 
return 0;
@@ -377,6 +376,13 @@ static __maybe_unused int gpu_i2c_resume(struct device 
*dev)
struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
 
gpu_enable_i2c_bus(i2cd);
+   /*
+* Runtime resume ccgx client so that it can see for any
+* connector change event. Old ccg firmware has known
+* issue of not triggering interrupt when a device is
+* connected to runtime resume the controller.
+*/
+   pm_request_resume(&i2cd->ccgx_client->dev);
return 0;
 }
 
-- 
2.17.1



[PATCH v5 3/5] usb: typec: ucsi: ccg: enable runtime pm support

2019-06-07 Thread Ajay Gupta
From: Ajay Gupta 

The change enables runtime pm support to UCSI CCG driver.
Added ucsi_resume() function to enable notification after
system reusme. Exported both ucsi_resume() and ucsi_send_command()
symbols in ucsi.c for modular build.

Signed-off-by: Ajay Gupta 
Acked-by: Heikki Krogerus 
---
Changes from v4->v5 : None

 drivers/usb/typec/ucsi/ucsi.c | 10 
 drivers/usb/typec/ucsi/ucsi.h |  1 +
 drivers/usb/typec/ucsi/ucsi_ccg.c | 38 +++
 3 files changed, 49 insertions(+)

diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index 7850b851cecd..ba288b964dc8 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -206,7 +206,17 @@ int ucsi_send_command(struct ucsi *ucsi, struct 
ucsi_control *ctrl,
 
return ret;
 }
+EXPORT_SYMBOL_GPL(ucsi_send_command);
 
+int ucsi_resume(struct ucsi *ucsi)
+{
+   struct ucsi_control ctrl;
+
+   /* Restore UCSI notification enable mask after system resume */
+   UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_ALL);
+   return ucsi_send_command(ucsi, &ctrl, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(ucsi_resume);
 /* -- 
*/
 
 void ucsi_altmode_update_active(struct ucsi_connector *con)
diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h
index 1e2981aef629..de87d0b8319d 100644
--- a/drivers/usb/typec/ucsi/ucsi.h
+++ b/drivers/usb/typec/ucsi/ucsi.h
@@ -430,6 +430,7 @@ int ucsi_send_command(struct ucsi *ucsi, struct 
ucsi_control *ctrl,
  void *retval, size_t size);
 
 void ucsi_altmode_update_active(struct ucsi_connector *con);
+int ucsi_resume(struct ucsi *ucsi);
 
 #if IS_ENABLED(CONFIG_TYPEC_DP_ALTMODE)
 struct typec_altmode *
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
index 9d46aa9e4e35..b15bc6c29c46 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -14,6 +14,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #include 
 #include "ucsi.h"
@@ -210,6 +212,7 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, 
u32 len)
if (quirks && quirks->max_read_len)
max_read_len = quirks->max_read_len;
 
+   pm_runtime_get_sync(uc->dev);
while (rem_len > 0) {
msgs[1].buf = &data[len - rem_len];
rlen = min_t(u16, rem_len, max_read_len);
@@ -218,12 +221,14 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+   pm_runtime_put_sync(uc->dev);
return status;
}
rab += rlen;
rem_len -= rlen;
}
 
+   pm_runtime_put_sync(uc->dev);
return 0;
 }
 
@@ -249,13 +254,16 @@ static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
msgs[0].len = len + sizeof(rab);
msgs[0].buf = buf;
 
+   pm_runtime_get_sync(uc->dev);
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+   pm_runtime_put_sync(uc->dev);
kfree(buf);
return status;
}
 
+   pm_runtime_put_sync(uc->dev);
kfree(buf);
return 0;
 }
@@ -1134,6 +1142,10 @@ static int ucsi_ccg_probe(struct i2c_client *client,
if (status)
dev_err(uc->dev, "cannot create sysfs group: %d\n", status);
 
+   pm_runtime_set_active(uc->dev);
+   pm_runtime_enable(uc->dev);
+   pm_runtime_idle(uc->dev);
+
return 0;
 }
 
@@ -1143,6 +1155,7 @@ static int ucsi_ccg_remove(struct i2c_client *client)
 
cancel_work_sync(&uc->work);
ucsi_unregister_ppm(uc->ucsi);
+   pm_runtime_disable(uc->dev);
free_irq(uc->irq, uc);
sysfs_remove_group(&uc->dev->kobj, &ucsi_ccg_attr_group);
 
@@ -1155,9 +1168,34 @@ static const struct i2c_device_id ucsi_ccg_device_id[] = 
{
 };
 MODULE_DEVICE_TABLE(i2c, ucsi_ccg_device_id);
 
+static int ucsi_ccg_resume(struct device *dev)
+{
+   struct i2c_client *client = to_i2c_client(dev);
+   struct ucsi_ccg *uc = i2c_get_clientdata(client);
+
+   return ucsi_resume(uc->ucsi);
+}
+
+static int ucsi_ccg_runtime_suspend(struct device *dev)
+{
+   return 0;
+}
+
+static int ucsi_ccg_runtime_resume(struct device *dev)
+{
+   return 0;
+}
+
+static const struct dev_pm_ops ucsi_ccg_pm = {
+   .resume = ucsi_ccg_resume,
+   .runtime_suspend = ucsi_ccg_runtime_suspend,
+  

[PATCH v5 2/5] i2c: nvidia-gpu: add runtime pm support

2019-06-07 Thread Ajay Gupta
From: Ajay Gupta 

Enable runtime pm support with autosuspend delay of three second.
This is to make sure I2C client device Cypress CCGx has completed
all transaction.

Signed-off-by: Ajay Gupta 
---
Changes from v4->v5:
- Removed extra comments for gpu_i2c_suspend() based on
Wolfram's comment.

 drivers/i2c/busses/i2c-nvidia-gpu.c | 22 +-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
index 7678a460bf9a..364244ffb5bf 100644
--- a/drivers/i2c/busses/i2c-nvidia-gpu.c
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -176,6 +176,7 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
 * The controller supports maximum 4 byte read due to known
 * limitation of sending STOP after every read.
 */
+   pm_runtime_get_sync(i2cd->dev);
for (i = 0; i < num; i++) {
if (msgs[i].flags & I2C_M_RD) {
/* program client address before starting read */
@@ -217,6 +218,8 @@ static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
if (status2 < 0)
dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
}
+   pm_runtime_mark_last_busy(i2cd->dev);
+   pm_runtime_put_autosuspend(i2cd->dev);
return status;
 }
 
@@ -336,6 +339,11 @@ static int gpu_i2c_probe(struct pci_dev *pdev, const 
struct pci_device_id *id)
goto del_adapter;
}
 
+   pm_runtime_set_autosuspend_delay(&pdev->dev, 3000);
+   pm_runtime_use_autosuspend(&pdev->dev);
+   pm_runtime_put_autosuspend(&pdev->dev);
+   pm_runtime_allow(&pdev->dev);
+
return 0;
 
 del_adapter:
@@ -349,10 +357,21 @@ static void gpu_i2c_remove(struct pci_dev *pdev)
 {
struct gpu_i2c_dev *i2cd = dev_get_drvdata(&pdev->dev);
 
+   pm_runtime_get_noresume(i2cd->dev);
i2c_del_adapter(&i2cd->adapter);
pci_free_irq_vectors(pdev);
 }
 
+/*
+ * We need gpu_i2c_suspend() even if it is stub, for runtime pm to work
+ * correctly. Without it, lspci shows runtime pm status as "D0" for the card.
+ * Documentation/power/pci.txt also insists for driver to provide this.
+ */
+static __maybe_unused int gpu_i2c_suspend(struct device *dev)
+{
+   return 0;
+}
+
 static __maybe_unused int gpu_i2c_resume(struct device *dev)
 {
struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
@@ -361,7 +380,8 @@ static __maybe_unused int gpu_i2c_resume(struct device *dev)
return 0;
 }
 
-static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, NULL, gpu_i2c_resume, NULL);
+static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, gpu_i2c_suspend, gpu_i2c_resume,
+   NULL);
 
 static struct pci_driver gpu_i2c_driver = {
.name   = "nvidia-gpu",
-- 
2.17.1



[PATCH v5 5/5] usb: typec: ucsi: ccg: add runtime pm workaround

2019-06-07 Thread Ajay Gupta
From: Ajay Gupta 

Cypress USB Type-C CCGx controller firmware version 3.1.10
(which is being used in many NVIDIA GPU cards) has known issue of
not triggering interrupt when a USB device is hot plugged to runtime
resume the controller. If any GPU card gets latest kernel with runtime
pm support but does not get latest fixed firmware then also it should
continue to work and therefore a workaround is required to check for
any connector change event.

The workaround is that i2c bus driver will call pm_request_resume()
to runtime resume ucsi_ccg driver. CCG driver will call the ISR
for any connector change event for NVIDIA GPU card and only if it has
old CCG firmware with the known issue.

Signed-off-by: Ajay Gupta 
Acked-by: Heikki Krogerus 
---
Changes from v4->v5: None

 drivers/usb/typec/ucsi/ucsi_ccg.c | 80 +--
 1 file changed, 76 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
index b15bc6c29c46..a5b81c011148 100644
--- a/drivers/usb/typec/ucsi/ucsi_ccg.c
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -109,12 +109,21 @@ struct version_format {
__le16 build;
u8 patch;
u8 ver;
+#define CCG_VERSION_PATCH(x) ((x) << 16)
+#define CCG_VERSION(x) ((x) << 24)
 #define CCG_VERSION_MIN_SHIFT (0)
 #define CCG_VERSION_MIN_MASK (0xf << CCG_VERSION_MIN_SHIFT)
 #define CCG_VERSION_MAJ_SHIFT (4)
 #define CCG_VERSION_MAJ_MASK (0xf << CCG_VERSION_MAJ_SHIFT)
 } __packed;
 
+/*
+ * Firmware version 3.1.10 or earlier, built for NVIDIA has known issue
+ * of missing interrupt when a device is connected for runtime resume
+ */
+#define CCG_FW_BUILD_NVIDIA(('n' << 8) | 'v')
+#define CCG_OLD_FW_VERSION (CCG_VERSION(0x31) | CCG_VERSION_PATCH(10))
+
 struct version_info {
struct version_format base;
struct version_format app;
@@ -172,6 +181,7 @@ struct ucsi_ccg {
struct ccg_dev_info info;
/* version info for boot, primary and secondary */
struct version_info version[FW2 + 1];
+   u32 fw_version;
/* CCG HPI communication flags */
unsigned long flags;
 #define RESET_PENDING  0
@@ -185,6 +195,8 @@ struct ucsi_ccg {
 
/* fw build with vendor information */
u16 fw_build;
+   bool run_isr; /* flag to call ISR routine during resume */
+   struct work_struct pm_work;
 };
 
 static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
@@ -212,6 +224,18 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
if (quirks && quirks->max_read_len)
max_read_len = quirks->max_read_len;
 
+   if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
+   uc->fw_version <= CCG_OLD_FW_VERSION) {
+   mutex_lock(&uc->lock);
+   /*
+* Do not schedule pm_work to run ISR in
+* ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
+* since we are already in ISR path.
+*/
+   uc->run_isr = false;
+   mutex_unlock(&uc->lock);
+   }
+
pm_runtime_get_sync(uc->dev);
while (rem_len > 0) {
msgs[1].buf = &data[len - rem_len];
@@ -254,6 +278,18 @@ static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 
*data, u32 len)
msgs[0].len = len + sizeof(rab);
msgs[0].buf = buf;
 
+   if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
+   uc->fw_version <= CCG_OLD_FW_VERSION) {
+   mutex_lock(&uc->lock);
+   /*
+* Do not schedule pm_work to run ISR in
+* ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
+* since we are already in ISR path.
+*/
+   uc->run_isr = false;
+   mutex_unlock(&uc->lock);
+   }
+
pm_runtime_get_sync(uc->dev);
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) {
@@ -383,6 +419,13 @@ static irqreturn_t ccg_irq_handler(int irq, void *data)
return IRQ_HANDLED;
 }
 
+static void ccg_pm_workaround_work(struct work_struct *pm_work)
+{
+   struct ucsi_ccg *uc = container_of(pm_work, struct ucsi_ccg, pm_work);
+
+   ucsi_notify(uc->ucsi);
+}
+
 static int get_fw_info(struct ucsi_ccg *uc)
 {
int err;
@@ -392,6 +435,9 @@ static int get_fw_info(struct ucsi_ccg *uc)
if (err < 0)
return err;
 
+   uc->fw_version = CCG_VERSION(uc->version[FW2].app.ver) |
+   CCG_VERSION_PATCH(uc->version[FW2].app.patch);
+
err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info),
   sizeof(uc->info));
if (err < 0)
@@ -740,11 +786,12 @@ static bool ccg_check_fw_version(struct ucsi_ccg *uc, 
const char

[RFC] usb: typec: ucsi: add support for separate DP altmode devices

2019-06-27 Thread Ajay Gupta
CCGx controller used on NVIDIA GPU card has two separate display
altmode for two DP pin assignments. UCSI specification doesn't
prohibits using separate display altmode.

Current UCSI Type-C framework expects only one display altmode for
all DP pin assignment. This patch squashes two separate display
altmode into single altmode to support controllers with separate
display altmode. We first read all the alternate modes of connector
and then run through it to know if there are separate display
altmodes. If so, it prepares a new port altmode set after squashing
two or more separate altmodes into one.

Signed-off-by: Ajay Gupta 
---
 drivers/usb/typec/ucsi/ucsi.c | 191 +-
 drivers/usb/typec/ucsi/ucsi.h |  12 +++
 2 files changed, 199 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index ba288b964dc8..491b5c925a90 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -39,8 +39,27 @@
  */
 #define UCSI_SWAP_TIMEOUT_MS   5000
 
+static void ucsi_update_get_current_cam_cmd(struct ucsi_connector *con,
+   struct ucsi_data *data)
+{
+   u8 cam, new_cam;
+
+   if (data->cci.data_length == 0x1) {
+   cam = data->message_in[0];
+   new_cam = con->port_alt[cam].linked_idx;
+   data->message_in[0] = new_cam;
+   con->new_port_alt[new_cam].active_idx = cam;
+   }
+}
+
 static inline int ucsi_sync(struct ucsi *ucsi)
 {
+   struct ucsi_connector *con = ucsi->connector;
+   struct ucsi_data *data = ucsi->ppm->data;
+
+   if (data->ctrl.alt.cmd == UCSI_GET_CURRENT_CAM && con->has_multiple_dp)
+   ucsi_update_get_current_cam_cmd(con, data);
+
if (ucsi->ppm && ucsi->ppm->sync)
return ucsi->ppm->sync(ucsi->ppm);
return 0;
@@ -101,14 +120,57 @@ static int ucsi_ack(struct ucsi *ucsi, u8 ack)
return ret;
 }
 
+static void ucsi_update_set_new_cam_cmd(struct ucsi_connector *con,
+   struct ucsi_control *ctrl)
+{
+   struct new_ucsi_altmode *new_port, *port;
+   struct typec_altmode *partner = NULL;
+   u64 cmd;
+   u8 new_cam, cam;
+   bool enter_new_mode;
+   int i, j;
+
+   cmd = ctrl->raw_cmd;
+   new_cam = (cmd >> 24) & 0xff;
+   new_port = &con->new_port_alt[new_cam];
+   cam = new_port->linked_idx;
+   enter_new_mode = (cmd >> 23) & 1;
+
+   if (cam == UCSI_MULTI_LINKED_INDEX) {
+   if (enter_new_mode) {
+   port = con->port_alt;
+   for (i = 0; con->partner_altmode[i]; i++) {
+   partner = con->partner_altmode[i];
+   if (partner->svid == new_port->svid)
+   break;
+   }
+   for (j = 0; port[j].svid; j++)
+   if (partner && port[j].svid == partner->svid &&
+   port[j].mid & partner->vdo)
+   break;
+   cam = j;
+   new_port->active_idx = cam;
+   } else {
+   cam = new_port->active_idx;
+   }
+   }
+   cmd &= ~(0xff << 24);
+   cmd |= (cam << 24);
+   ctrl->raw_cmd = cmd;
+}
+
 static int ucsi_run_command(struct ucsi *ucsi, struct ucsi_control *ctrl,
void *data, size_t size)
 {
struct ucsi_control _ctrl;
+   struct ucsi_connector *con = ucsi->connector;
u8 data_length;
u16 error;
int ret;
 
+   if (ctrl->alt.cmd == UCSI_SET_NEW_CAM && con->has_multiple_dp)
+   ucsi_update_set_new_cam_cmd(con, ctrl);
+
ret = ucsi_command(ucsi, ctrl);
if (ret)
goto err;
@@ -364,10 +426,24 @@ static int ucsi_register_altmodes(struct ucsi_connector 
*con, u8 recipient)
 
for (i = 0; i < max_altmodes;) {
memset(alt, 0, sizeof(alt));
-   UCSI_CMD_GET_ALTERNATE_MODES(ctrl, recipient, con->num, i, 1);
-   len = ucsi_run_command(con->ucsi, &ctrl, alt, sizeof(alt));
-   if (len <= 0)
-   return len;
+
+   if (recipient == UCSI_RECIPIENT_CON) {
+   if (con->has_multiple_dp) {
+   alt[0].svid = con->new_port_alt[i].svid;
+   alt[0].mid = con->new_port_alt[i].mid;
+   } else {
+   alt[0].svid = con->port_alt[i].svid;
+   alt[0].mid = con->port_alt[i].mid;
+  

Re: [RFC] usb: typec: ucsi: add support for separate DP altmode devices

2019-06-28 Thread Ajay Gupta
Hi Heikki,

> On Jun 28, 2019, at 3:47 AM, Heikki Krogerus 
>  wrote:
> 
>> On Thu, Jun 27, 2019 at 10:45:47PM -0700, Ajay Gupta wrote:
>> CCGx controller used on NVIDIA GPU card has two separate display
>> altmode for two DP pin assignments. UCSI specification doesn't
>> prohibits using separate display altmode.
>> 
>> Current UCSI Type-C framework expects only one display altmode for
>> all DP pin assignment. This patch squashes two separate display
>> altmode into single altmode to support controllers with separate
>> display altmode. We first read all the alternate modes of connector
>> and then run through it to know if there are separate display
>> altmodes. If so, it prepares a new port altmode set after squashing
>> two or more separate altmodes into one.
> 
> I don't have any better ideas how to solve this at them moment.
> Therefore, I don't have a problem with going forward with this.

Thanks, please review the change and provide any comment. I will anyways repost 
this as a patch.

Thanks 
> nvpublic 
> But
> please note, that we are already at -rc6, so nothing is going to
> happen for a while. I'll away for the next four weeks.
> 
>> Signed-off-by: Ajay Gupta 
>> ---
>> drivers/usb/typec/ucsi/ucsi.c | 191 +-
>> drivers/usb/typec/ucsi/ucsi.h |  12 +++
>> 2 files changed, 199 insertions(+), 4 deletions(-)
>> 
>> diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
>> index ba288b964dc8..491b5c925a90 100644
>> --- a/drivers/usb/typec/ucsi/ucsi.c
>> +++ b/drivers/usb/typec/ucsi/ucsi.c
>> @@ -39,8 +39,27 @@
>>  */
>> #define UCSI_SWAP_TIMEOUT_MS5000
>> 
>> +static void ucsi_update_get_current_cam_cmd(struct ucsi_connector *con,
>> +struct ucsi_data *data)
>> +{
>> +u8 cam, new_cam;
>> +
>> +if (data->cci.data_length == 0x1) {
>> +cam = data->message_in[0];
>> +new_cam = con->port_alt[cam].linked_idx;
>> +data->message_in[0] = new_cam;
>> +con->new_port_alt[new_cam].active_idx = cam;
>> +}
>> +}
>> +
>> static inline int ucsi_sync(struct ucsi *ucsi)
>> {
>> +struct ucsi_connector *con = ucsi->connector;
>> +struct ucsi_data *data = ucsi->ppm->data;
>> +
>> +if (data->ctrl.alt.cmd == UCSI_GET_CURRENT_CAM && con->has_multiple_dp)
>> +ucsi_update_get_current_cam_cmd(con, data);
>> +
>>if (ucsi->ppm && ucsi->ppm->sync)
>>return ucsi->ppm->sync(ucsi->ppm);
>>return 0;
>> @@ -101,14 +120,57 @@ static int ucsi_ack(struct ucsi *ucsi, u8 ack)
>>return ret;
>> }
>> 
>> +static void ucsi_update_set_new_cam_cmd(struct ucsi_connector *con,
>> +struct ucsi_control *ctrl)
>> +{
>> +struct new_ucsi_altmode *new_port, *port;
>> +struct typec_altmode *partner = NULL;
>> +u64 cmd;
>> +u8 new_cam, cam;
>> +bool enter_new_mode;
>> +int i, j;
>> +
>> +cmd = ctrl->raw_cmd;
>> +new_cam = (cmd >> 24) & 0xff;
>> +new_port = &con->new_port_alt[new_cam];
>> +cam = new_port->linked_idx;
>> +enter_new_mode = (cmd >> 23) & 1;
>> +
>> +if (cam == UCSI_MULTI_LINKED_INDEX) {
>> +if (enter_new_mode) {
>> +port = con->port_alt;
>> +for (i = 0; con->partner_altmode[i]; i++) {
>> +partner = con->partner_altmode[i];
>> +if (partner->svid == new_port->svid)
>> +break;
>> +}
>> +for (j = 0; port[j].svid; j++)
>> +if (partner && port[j].svid == partner->svid &&
>> +port[j].mid & partner->vdo)
>> +break;
>> +cam = j;
>> +new_port->active_idx = cam;
>> +} else {
>> +cam = new_port->active_idx;
>> +}
>> +}
>> +cmd &= ~(0xff << 24);
>> +cmd |= (cam << 24);
>> +ctrl->raw_cmd = cmd;
>> +}
>> +
>> static int ucsi_run_command(struct ucsi *ucsi, struct ucsi_control *ctrl,
>>void *data, size_t size)
>> {
>>struct ucsi_control _ctrl;
>> +struct ucsi_connector *con = ucsi->connector;
>>u8 data_length;
>>u16 error;
>>int ret;
>> 

[PATCH] usb: typec: ucsi: add support for separate DP altmode devices

2019-06-28 Thread Ajay Gupta
From: Ajay Gupta 

CCGx controller used on NVIDIA GPU card has two separate display
altmode for two DP pin assignments. UCSI specification doesn't
prohibits using separate display altmode.

Current UCSI Type-C framework expects only one display altmode for
all DP pin assignment. This patch squashes two separate display
altmode into single altmode to support controllers with separate
display altmode. We first read all the alternate modes of connector
and then run through it to know if there are separate display
altmodes. If so, it prepares a new port altmode set after squashing
two or more separate altmodes into one.

Signed-off-by: Ajay Gupta 
---
Original discussion on this issue is at [1]
RFC patch version is at [2]
Changes from RFC :
- Update logic to prioritixe pin E -> D -> C
- Fix a bug in ucsi_sync()

1. https://marc.info/?l=linux-usb&m=154905866830998&w=2 
2. https://marc.info/?l=linux-usb&m=156170104116037&w=2

 drivers/usb/typec/ucsi/ucsi.c | 210 --
 drivers/usb/typec/ucsi/ucsi.h |  12 ++
 2 files changed, 215 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index ba288b964dc8..e673e95e9f6c 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -39,11 +39,35 @@
  */
 #define UCSI_SWAP_TIMEOUT_MS   5000
 
+static void ucsi_update_get_current_cam_cmd(struct ucsi_connector *con,
+   struct ucsi_data *data)
+{
+   u8 cam, new_cam;
+
+   if (data->cci.data_length == 0x1) {
+   cam = data->message_in[0];
+   new_cam = con->port_alt[cam].linked_idx;
+   data->message_in[0] = new_cam;
+   con->new_port_alt[new_cam].active_idx = cam;
+   }
+}
+
 static inline int ucsi_sync(struct ucsi *ucsi)
 {
-   if (ucsi->ppm && ucsi->ppm->sync)
-   return ucsi->ppm->sync(ucsi->ppm);
-   return 0;
+   struct ucsi_connector *con = ucsi->connector;
+   struct ucsi_data *data = ucsi->ppm->data;
+   int ret = 0;
+
+   if (ucsi->ppm && ucsi->ppm->sync) {
+   ret = ucsi->ppm->sync(ucsi->ppm);
+   if (ret)
+   return ret;
+   }
+
+   if (data->ctrl.alt.cmd == UCSI_GET_CURRENT_CAM && con->has_multiple_dp)
+   ucsi_update_get_current_cam_cmd(con, data);
+
+   return ret;
 }
 
 static int ucsi_command(struct ucsi *ucsi, struct ucsi_control *ctrl)
@@ -101,14 +125,65 @@ static int ucsi_ack(struct ucsi *ucsi, u8 ack)
return ret;
 }
 
+static void ucsi_update_set_new_cam_cmd(struct ucsi_connector *con,
+   struct ucsi_control *ctrl)
+{
+   struct new_ucsi_altmode *new_port, *port;
+   struct typec_altmode *alt = NULL;
+   u64 cmd;
+   u8 new_cam, cam, pin;
+   bool enter_new_mode;
+   int i, j, k = 0xff;
+
+   cmd = ctrl->raw_cmd;
+   new_cam = (cmd >> 24) & 0xff;
+   new_port = &con->new_port_alt[new_cam];
+   cam = new_port->linked_idx;
+   enter_new_mode = (cmd >> 23) & 1;
+
+   if (cam == UCSI_MULTI_LINKED_INDEX) {
+   if (enter_new_mode) {
+   port = con->port_alt;
+   for (i = 0; con->partner_altmode[i]; i++) {
+   alt = con->partner_altmode[i];
+   if (alt->svid == new_port->svid)
+   break;
+   }
+   for (j = 0; port[j].svid; j++) {
+   pin = DP_CONF_GET_PIN_ASSIGN(port[j].mid);
+   if (alt && port[j].svid == alt->svid &&
+   (pin & DP_CONF_GET_PIN_ASSIGN(alt->vdo))) {
+   /* prioritize pin E->D->C */
+   if (k == 0xff || (k != 0xff && pin >
+   DP_CONF_GET_PIN_ASSIGN(port[k].mid))
+   ) {
+   k = j;
+   }
+   }
+   }
+   cam = k;
+   new_port->active_idx = cam;
+   } else {
+   cam = new_port->active_idx;
+   }
+   }
+   cmd &= ~(0xff << 24);
+   cmd |= (cam << 24);
+   ctrl->raw_cmd = cmd;
+}
+
 static int ucsi_run_command(struct ucsi *ucsi, struct ucsi_control *ctrl,
void *data, size_t size)
 {
struct ucsi_control _ctrl;
+   struct ucsi_connector *con = ucsi->connector;
u8

[PATCH v2] usb: typec: ucsi: add support for separate DP altmode devices

2019-08-05 Thread Ajay Gupta
From: Ajay Gupta 

CCGx controller used on NVIDIA GPU card has two separate display
altmode for two DP pin assignments. UCSI specification doesn't
prohibits using separate display altmode.

Current UCSI Type-C framework expects only one display altmode for
all DP pin assignment. This patch squashes two separate display
altmode into single altmode to support controllers with separate
display altmode. We first read all the alternate modes of connector
and then run through it to know if there are separate display
altmodes. If so, it prepares a new port altmode set after squashing
two or more separate altmodes into one.

Signed-off-by: Ajay Gupta 
---
Original discussion on this issue is at [1]

Change from v1->v2
- Fix ucsi->ppm NULL check in ucsi_sync based on
comment from an automated email from someone (I lost the email).

1. https://marc.info/?l=linux-usb&m=154905866830998&w=2

 drivers/usb/typec/ucsi/ucsi.c | 212 --
 drivers/usb/typec/ucsi/ucsi.h |  12 ++
 2 files changed, 217 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index ba288b964dc8..68ea66fcaa0e 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -39,11 +39,37 @@
  */
 #define UCSI_SWAP_TIMEOUT_MS   5000
 
+static void ucsi_update_get_current_cam_cmd(struct ucsi_connector *con,
+   struct ucsi_data *data)
+{
+   u8 cam, new_cam;
+
+   if (data->cci.data_length == 0x1) {
+   cam = data->message_in[0];
+   new_cam = con->port_alt[cam].linked_idx;
+   data->message_in[0] = new_cam;
+   con->new_port_alt[new_cam].active_idx = cam;
+   }
+}
+
 static inline int ucsi_sync(struct ucsi *ucsi)
 {
-   if (ucsi->ppm && ucsi->ppm->sync)
-   return ucsi->ppm->sync(ucsi->ppm);
-   return 0;
+   struct ucsi_connector *con = ucsi->connector;
+   struct ucsi_data *data;
+   int ret = 0;
+
+   if (ucsi->ppm && ucsi->ppm->sync) {
+   ret = ucsi->ppm->sync(ucsi->ppm);
+   if (ret)
+   return ret;
+
+   data = ucsi->ppm->data;
+   if (data->ctrl.alt.cmd == UCSI_GET_CURRENT_CAM &&
+   con->has_multiple_dp)
+   ucsi_update_get_current_cam_cmd(con, data);
+   }
+
+   return ret;
 }
 
 static int ucsi_command(struct ucsi *ucsi, struct ucsi_control *ctrl)
@@ -101,14 +127,65 @@ static int ucsi_ack(struct ucsi *ucsi, u8 ack)
return ret;
 }
 
+static void ucsi_update_set_new_cam_cmd(struct ucsi_connector *con,
+   struct ucsi_control *ctrl)
+{
+   struct new_ucsi_altmode *new_port, *port;
+   struct typec_altmode *alt = NULL;
+   u64 cmd;
+   u8 new_cam, cam, pin;
+   bool enter_new_mode;
+   int i, j, k = 0xff;
+
+   cmd = ctrl->raw_cmd;
+   new_cam = (cmd >> 24) & 0xff;
+   new_port = &con->new_port_alt[new_cam];
+   cam = new_port->linked_idx;
+   enter_new_mode = (cmd >> 23) & 1;
+
+   if (cam == UCSI_MULTI_LINKED_INDEX) {
+   if (enter_new_mode) {
+   port = con->port_alt;
+   for (i = 0; con->partner_altmode[i]; i++) {
+   alt = con->partner_altmode[i];
+   if (alt->svid == new_port->svid)
+   break;
+   }
+   for (j = 0; port[j].svid; j++) {
+   pin = DP_CONF_GET_PIN_ASSIGN(port[j].mid);
+   if (alt && port[j].svid == alt->svid &&
+   (pin & DP_CONF_GET_PIN_ASSIGN(alt->vdo))) {
+   /* prioritize pin E->D->C */
+   if (k == 0xff || (k != 0xff && pin >
+   DP_CONF_GET_PIN_ASSIGN(port[k].mid))
+   ) {
+   k = j;
+   }
+   }
+   }
+   cam = k;
+   new_port->active_idx = cam;
+   } else {
+   cam = new_port->active_idx;
+   }
+   }
+   cmd &= ~(0xff << 24);
+   cmd |= (cam << 24);
+   ctrl->raw_cmd = cmd;
+}
+
 static int ucsi_run_command(struct ucsi *ucsi, struct ucsi_control *ctrl,
void *data, size_t size)
 {
struct ucsi_control _ctrl;
+   struct ucsi_connector *con = ucsi->connector;
u8 da

[PATCH] usb: xhci: increase CRS timeout value

2018-06-07 Thread Ajay Gupta
Some controllers take almost 55ms to complete controller
restore state (CRS).
There is no timeout limit mentioned in xhci specification so
fix the issue by increasing the timeout limit to 55ms

Signed-off-by: Ajay Gupta 
Signed-off-by: Nagaraj Annaiah 
---
 drivers/usb/host/xhci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 8c8da2d..44b1af5 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1044,7 +1044,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
command |= CMD_CRS;
writel(command, &xhci->op_regs->command);
if (xhci_handshake(&xhci->op_regs->status,
- STS_RESTORE, 0, 10 * 1000)) {
+ STS_RESTORE, 0, 55 * 1000)) {
xhci_warn(xhci, "WARN: xHC restore state timeout\n");
spin_unlock_irq(&xhci->lock);
return -ETIMEDOUT;
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2] usb: xhci: increase CRS timeout value

2018-06-11 Thread Ajay Gupta
Some controllers take almost 55ms to complete controller
restore state (CRS).
There is no timeout limit mentioned in xhci specification so
fixing the issue by increasing the timeout limit to 55ms

Signed-off-by: Ajay Gupta 
Signed-off-by: Nagaraj Annaiah 
---
 drivers/usb/host/xhci.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 8c8da2d..fa7bd71 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1043,8 +1043,13 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
command = readl(&xhci->op_regs->command);
command |= CMD_CRS;
writel(command, &xhci->op_regs->command);
+   /* Some controllers take upto 55+ ms to complete
+* the controller restore so setting the timeout to
+* 100ms. Xhci specification doesn't mention any
+* timeout value.
+*/
if (xhci_handshake(&xhci->op_regs->status,
- STS_RESTORE, 0, 10 * 1000)) {
+ STS_RESTORE, 0, 100 * 1000)) {
xhci_warn(xhci, "WARN: xHC restore state timeout\n");
spin_unlock_irq(&xhci->lock);
return -ETIMEDOUT;
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v3] usb: xhci: increase CRS timeout value

2018-06-11 Thread Ajay Gupta
Some controllers take almost 55ms to complete controller
restore state (CRS).
There is no timeout limit mentioned in xhci specification so
fixing the issue by increasing the timeout limit to 100ms

Signed-off-by: Ajay Gupta 
Signed-off-by: Nagaraj Annaiah 
---
Changes from v2->v3
Updated commit message for timeout value to 100ms

Changes from v1->v2
Updated timeout value from 55 to 100ms and added a comment.
 drivers/usb/host/xhci.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 8c8da2d..fa7bd71 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1043,8 +1043,13 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
command = readl(&xhci->op_regs->command);
command |= CMD_CRS;
writel(command, &xhci->op_regs->command);
+   /* Some controllers take upto 55+ ms to complete
+* the controller restore so setting the timeout to
+* 100ms. Xhci specification doesn't mention any
+* timeout value.
+*/
if (xhci_handshake(&xhci->op_regs->status,
- STS_RESTORE, 0, 10 * 1000)) {
+ STS_RESTORE, 0, 100 * 1000)) {
xhci_warn(xhci, "WARN: xHC restore state timeout\n");
spin_unlock_irq(&xhci->lock);
return -ETIMEDOUT;
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v2] USB: serial: ftdi_sio: Add MTP NVM support

2018-06-21 Thread Ajay Gupta
Hi Loic

On 6/21/18, Loic Poulain  wrote:
> Most of FTDI's devices have an EEPROM which records FTDI devices
> configuration setting (e.g. the VID, PID, I/O config...) and user
> data. FT230R chip integrates a 128-byte eeprom, FT230X a 2048-byte
> eeprom...
>
> This patch adds support for FTDI EEPROM read/write via USB control
> transfers and register a new nvm device to the nvmem core.
>
> This permits to expose the eeprom as a sysfs file, allowing userspace
> to read/modify FTDI configuration and its user data without having to
> rely on a specific userspace USB driver.
>
> Moreover, any upcoming new tentative to add CBUS GPIO support could
> integrate CBUS EEPROM configuration reading in order to determine
> which of the CBUS pins are available as GPIO.
>
> Signed-off-by: Loic Poulain 
> ---
>  v2: Use ifdef instead of IS_ENABLED
>  error message in case of nvmem registering failure
>  Fix space/tab in Kconfig
>
>  drivers/usb/serial/Kconfig|  13 -
>  drivers/usb/serial/ftdi_sio.c | 111
> ++
>  drivers/usb/serial/ftdi_sio.h |  28 +++
>  3 files changed, 151 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
> index 533f127..f05af5f 100644
> --- a/drivers/usb/serial/Kconfig
> +++ b/drivers/usb/serial/Kconfig
> @@ -153,7 +153,7 @@ config USB_SERIAL_CYPRESS_M8
>
> Supported microcontrollers in the CY4601 family are:
>   CY7C63741 CY7C63742 CY7C63743 CY7C64013
> - 
> +
There is no change here so please remove it.

> To compile this driver as a module, choose M here: the
> module will be called cypress_m8.
>
> @@ -181,6 +181,17 @@ config USB_SERIAL_FTDI_SIO
> To compile this driver as a module, choose M here: the
> module will be called ftdi_sio.
>
> +config USB_SERIAL_FTDI_SIO_NVMEM
> + bool "FTDI MTP non-volatile memory support"
> + depends on USB_SERIAL_FTDI_SIO
> + select NVMEM
> + default y
> + help
> +   Say yes here to add support for the MTP non-volatile memory
> +   present on FTDI. Most of FTDI's devices have an EEPROM which
> +   records FTDI device's configuration setting as well as user
> +   data.
> +
>  config USB_SERIAL_VISOR
>   tristate "USB Handspring Visor / Palm m50x / Sony Clie Driver"
>   help
> diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
> index 7ea221d..9e242e8 100644
> --- a/drivers/usb/serial/ftdi_sio.c
> +++ b/drivers/usb/serial/ftdi_sio.c
> @@ -40,6 +40,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include "ftdi_sio.h"
>  #include "ftdi_sio_ids.h"
>
> @@ -73,6 +74,8 @@ struct ftdi_private {
>   unsigned int latency;   /* latency setting in use */
>   unsigned short max_packet_size;
>   struct mutex cfg_lock; /* Avoid mess by parallel calls of config ioctl()
> and change_speed() */
> +
> + struct nvmem_device *eeprom;
>  };
>
>  /* struct ftdi_sio_quirk is used by devices requiring special attention.
> */
> @@ -1529,6 +1532,104 @@ static int get_lsr_info(struct usb_serial_port
> *port,
>   return 0;
>  }
>
> +#ifdef CONFIG_USB_SERIAL_FTDI_SIO_NVMEM
> +
> +static int write_eeprom(void *priv, unsigned int off, void *_val, size_t
> bytes)
> +{
> + struct usb_serial_port *port = priv;
> + struct usb_serial *serial = port->serial;
> + struct usb_device *udev = serial->dev;
> + unsigned char *buf = _val;
> +
> + while (bytes) { /* bytes value is always a multiple of 2 */

We should add check that 'bytes' is always multiple of 2 otherwise in
case its not then there will be memory overrun due to buf[1] access
below.
while (bytes / 2) {
}

> + uint16_t val;
> + int rv;
> +
> + val = buf[0] + (buf[1] << 8);
> +
> + rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
> +  FTDI_SIO_WRITE_EEPROM_REQUEST,
> +  FTDI_SIO_WRITE_EEPROM_REQUEST_TYPE,
> +  val, off / 2, NULL, 0, WDR_TIMEOUT);
> + if (rv < 0)
> + return rv;
> +
> + off += 2;
> + buf += 2;
> + bytes -= 2;
> + }
> +
> + return 0;
> +}
> +
> +static int read_eeprom(void *priv, unsigned int off, void *val, size_t
> bytes)
> +{
> + struct usb_serial_port *port = priv;
> + struct usb_serial *serial = port->serial;
> + struct usb_device *udev = serial->dev;
> + unsigned char *buf = val;
> +
> + while (bytes) { /* bytes value is always a multiple of 2 */
same here

> + int rv;
> +
> + rv = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
> +  FTDI_SIO_READ_EEPROM_REQUEST,
> +  FTDI_SIO_READ_EEPROM_REQUEST_TYPE,
> +  0, off / 2, buf, 2, WDR_TIMEOUT);
> + if (rv < 0)
> +  

Re: [PATCH v6] USB: serial: ftdi_sio: Add MTP NVM support

2018-06-29 Thread Ajay Gupta
Hi Loic.
Thanks for fixing comments. Looks good to me now.

On 6/26/18, Loic Poulain  wrote:
> Most of FTDI's devices have an EEPROM which records FTDI devices
> configuration setting (e.g. the VID, PID, I/O config...) and user
> data. For example, FT232R and FTX chips have 128-byte and 2048-byte
> internal EEPROM respectively.
>
> This patch adds support for FTDI EEPROM read/write via USB control
> transfers and register a new nvm device to the nvmem core.
>
> This permits to expose the EEPROM as a sysfs file, allowing userspace
> to read/modify FTDI configuration and its user data without having to
> rely on a specific userspace USB driver.
>
> Moreover, any upcoming new tentative to add CBUS GPIO support could
> integrate CBUS EEPROM configuration reading in order to determine
> which of the CBUS pins are available as GPIO.
>
> Reviewed-by: Andy Shevchenko 
> Signed-off-by: Loic Poulain 

Reviewed-by: Ajay Gupta 
> ---
>  v2: Use ifdef instead of IS_ENABLED
>  error message in case of nvmem registering failure
>  Fix space/tab in Kconfig
>  v3: Make nvmem a child of the usb dev instead of the serial port
>  Add macros defining eeprom sizes
>  Check read/write size is a nultiple of the eeprom word-size
>  Remove useless change in Kconfig
>  v4: Reword commit message
>  Remove default-yes from Kconfig
>  Change includes ordering
>  Use default linux size defines
>  Use get_unaligned_le16 helper
>  Prepend EEPROM functions with ftdi_
>  Error message in ftdi_eeprom_register()
>  v5: Fix missing linux/sizes header
>  v6: Ordering new headers insertion
>  Remove unecessary additional buf pointer from read/write_eeprom
>
>  drivers/usb/serial/Kconfig|  10 
>  drivers/usb/serial/ftdi_sio.c | 118
> ++
>  drivers/usb/serial/ftdi_sio.h |  28 ++
>  3 files changed, 156 insertions(+)
>
> diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
> index 533f127..5747562 100644
> --- a/drivers/usb/serial/Kconfig
> +++ b/drivers/usb/serial/Kconfig
> @@ -181,6 +181,16 @@ config USB_SERIAL_FTDI_SIO
> To compile this driver as a module, choose M here: the
> module will be called ftdi_sio.
>
> +config USB_SERIAL_FTDI_SIO_NVMEM
> + bool "FTDI MTP non-volatile memory support"
> + depends on USB_SERIAL_FTDI_SIO
> + select NVMEM
> + help
> +   Say yes here to add support for the MTP non-volatile memory
> +   present on FTDI. Most of FTDI's devices have an EEPROM which
> +   records FTDI device's configuration setting as well as user
> +   data.
> +
>  config USB_SERIAL_VISOR
>   tristate "USB Handspring Visor / Palm m50x / Sony Clie Driver"
>   help
> diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
> index 7ea221d..34daa8c 100644
> --- a/drivers/usb/serial/ftdi_sio.c
> +++ b/drivers/usb/serial/ftdi_sio.c
> @@ -34,12 +34,17 @@
>  #include 
>  #include 
>  #include 
> +#include 
> +#include 
>  #include 
>  #include 
>  #include 
>  #include 
>  #include 
>  #include 
> +
> +#include 
> +
>  #include "ftdi_sio.h"
>  #include "ftdi_sio_ids.h"
>
> @@ -73,6 +78,8 @@ struct ftdi_private {
>   unsigned int latency;   /* latency setting in use */
>   unsigned short max_packet_size;
>   struct mutex cfg_lock; /* Avoid mess by parallel calls of config ioctl()
> and change_speed() */
> +
> + struct nvmem_device *eeprom;
>  };
>
>  /* struct ftdi_sio_quirk is used by devices requiring special attention.
> */
> @@ -1529,6 +1536,110 @@ static int get_lsr_info(struct usb_serial_port
> *port,
>   return 0;
>  }
>
> +#ifdef CONFIG_USB_SERIAL_FTDI_SIO_NVMEM
> +
> +static int ftdi_write_eeprom(void *priv, unsigned int off, void *val,
> +  size_t bytes)
> +{
> + struct usb_serial_port *port = priv;
> + struct usb_device *udev = port->serial->dev;
> +
> + if (bytes % 2) /* 16-bit eeprom */
> + return -EINVAL;
> +
> + while (bytes) {
> + int rv;
> +
> + rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
> +  FTDI_SIO_WRITE_EEPROM_REQUEST,
> +  FTDI_SIO_WRITE_EEPROM_REQUEST_TYPE,
> +  get_unaligned_le16(val), off / 2, NULL,
> +  0, WDR_TIMEOUT);
> + if (rv < 0)
> + return rv;
> +
> + off += 2;
> + val += 2;
> + b

[PATCH 1/2] i2c: buses: add i2c bus driver for NVIDIA GPU

2018-08-24 Thread Ajay Gupta
Latest NVIDIA GPU card has USB Type-C interface. There is a
Type-C controller which can be accessed over I2C.

This driver add I2C bus driver to communicate with Type-C controller.
I2C client driver will be part of USB Type-C UCSI driver.

Signed-off-by: Ajay Gupta 
---
 Documentation/i2c/busses/i2c-gpu |  18 ++
 MAINTAINERS  |   7 +
 drivers/i2c/busses/Kconfig   |   9 +
 drivers/i2c/busses/Makefile  |   1 +
 drivers/i2c/busses/i2c-gpu.c | 493 +++
 5 files changed, 528 insertions(+)
 create mode 100644 Documentation/i2c/busses/i2c-gpu
 create mode 100644 drivers/i2c/busses/i2c-gpu.c

diff --git a/Documentation/i2c/busses/i2c-gpu b/Documentation/i2c/busses/i2c-gpu
new file mode 100644
index 000..873ba34
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-gpu
@@ -0,0 +1,18 @@
+Kernel driver i2c-gpu
+
+Datasheet: not publicly available.
+
+Authors:
+   Ajay Gupta 
+
+Description
+---
+
+i2c-gpu is a driver for I2C controller included in NVIDIA Turing and later
+GPUs and it is used to communicate with Type-C controller on GPUs.
+
+If your 'lspci -v' listing shows something like the following,
+
+01:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device 1ad9 (rev a1)
+
+then this driver should support the I2C controller of your GPU.
diff --git a/MAINTAINERS b/MAINTAINERS
index efb08d7..ee137de 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6781,6 +6781,13 @@ L:   linux-a...@vger.kernel.org
 S: Maintained
 F: drivers/i2c/i2c-core-acpi.c
 
+I2C CONTROLLER DRIVER FOR NVIDIA GPU
+M: Ajay Gupta 
+L: linux-...@vger.kernel.org
+S: Maintained
+F: Documentation/i2c/busses/i2c-gpu
+F: drivers/i2c/busses/i2c-gpu.c
+
 I2C MUXES
 M: Peter Rosin 
 L: linux-...@vger.kernel.org
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 451d4ae..ff8b2d4 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -224,6 +224,15 @@ config I2C_NFORCE2_S4985
  This driver can also be built as a module.  If so, the module
  will be called i2c-nforce2-s4985.
 
+config I2C_GPU
+   tristate "NVIDIA GPU I2C controller"
+   depends on PCI
+   help
+ If you say yes to this option, support will be included for the
+ NVIDIA GPU I2C controller which is used to communicate with the GPU's
+ Type-C controller. This driver can also be built as a module called
+ i2c-gpu.ko.
+
 config I2C_SIS5595
tristate "SiS 5595"
depends on PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 18b26af..15d2894 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -140,5 +140,6 @@ obj-$(CONFIG_I2C_SIBYTE)+= i2c-sibyte.o
 obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o
 obj-$(CONFIG_SCx200_ACB)   += scx200_acb.o
 obj-$(CONFIG_I2C_FSI)  += i2c-fsi.o
+obj-$(CONFIG_I2C_GPU)  += i2c-gpu.o
 
 ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/busses/i2c-gpu.c b/drivers/i2c/busses/i2c-gpu.c
new file mode 100644
index 000..0fd2944
--- /dev/null
+++ b/drivers/i2c/busses/i2c-gpu.c
@@ -0,0 +1,493 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nvidia GPU I2C controller Driver
+ *
+ * Copyright (C) 2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta 
+ *
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* STATUS definitions  */
+#define STATUS_SUCCESS 0
+#define STATUS_UNSUCCESSFUL0x8000UL
+#define STATUS_TIMEOUT 0x8001UL
+#define STATUS_IO_DEVICE_ERROR 0x8002UL
+#define STATUS_IO_TIMEOUT  0x8004UL
+#define STATUS_IO_PREEMPTED0x8008UL
+
+/* Cypress Type-C controllers (CCGx) device */
+#define CCGX_I2C_DEV_ADDRESS   0x08
+
+/* I2C definitions */
+#define I2C_MST_CNTL   0x00
+#define I2C_MST_CNTL_GEN_START (1 << 0)
+#define I2C_MST_CNTL_GEN_STOP  (1 << 1)
+#define I2C_MST_CNTL_CMD_NONE  (0 << 2)
+#define I2C_MST_CNTL_CMD_READ  (1 << 2)
+#define I2C_MST_CNTL_CMD_WRITE (2 << 2)
+#define I2C_MST_CNTL_CMD_RESET (3 << 2)
+#define I2C_MST_CNTL_GEN_RAB   (1 << 4)
+#define I2C_MST_CNTL_BURST_SIZE_SHIFT  (6)
+#define I2C_MST_CNTL_GEN_NACK  (1 << 28)
+#define I2C_MST_CNTL_STATUS(3 << 29)
+#define I2C_MST_CNTL_STATUS_OKAY   (0 << 29)
+#define I2C_MST_CNTL_STATUS_NO_ACK (1 << 29)
+#define I2C_MST_CNTL_STATUS_TIMEOUT(2 << 29)
+#define I2C_MST_CNTL_STATUS_BUS_BUSY   (3 << 29)
+#define I2C_MST_CNTL_CYCLE_TRIGGER (1 << 31)
+
+#define I2C_M

[PATCH 2/2] usb: typec: ucsi: add support for Cypress CCGx

2018-08-24 Thread Ajay Gupta
Latest NVIDIA GPU cards have a Cypress CCGx Type-C controller
over I2C interface.

This UCSI I2C driver uses I2C bus driver interface for communicating
with Type-C controller.

Signed-off-by: Ajay Gupta 
---
 drivers/usb/typec/ucsi/Kconfig|  10 +
 drivers/usb/typec/ucsi/Makefile   |   2 +
 drivers/usb/typec/ucsi/ucsi_i2c_ccg.c | 591 ++
 3 files changed, 603 insertions(+)
 create mode 100644 drivers/usb/typec/ucsi/ucsi_i2c_ccg.c

diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig
index e36d6c7..5136aeb 100644
--- a/drivers/usb/typec/ucsi/Kconfig
+++ b/drivers/usb/typec/ucsi/Kconfig
@@ -23,6 +23,16 @@ config TYPEC_UCSI
 
 if TYPEC_UCSI
 
+config UCSI_I2C_CCG
+tristate "UCSI I2C Interface Driver for Cypress CCGx"
+   depends on I2C_GPU
+help
+  This driver enables UCSI support on NVIDIA GPUs that expose a
+ Cypress CCGx Type-C controller over I2C interface.
+
+  To compile the driver as a module, choose M here: the module will be
+  called ucsi_i2c_ccg.ko.
+
 config UCSI_ACPI
tristate "UCSI ACPI Interface Driver"
depends on ACPI
diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile
index 7afbea5..4439482 100644
--- a/drivers/usb/typec/ucsi/Makefile
+++ b/drivers/usb/typec/ucsi/Makefile
@@ -8,3 +8,5 @@ typec_ucsi-y:= ucsi.o
 typec_ucsi-$(CONFIG_TRACING)   += trace.o
 
 obj-$(CONFIG_UCSI_ACPI)+= ucsi_acpi.o
+
+obj-$(CONFIG_UCSI_I2C_CCG) += ucsi_i2c_ccg.o
diff --git a/drivers/usb/typec/ucsi/ucsi_i2c_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_i2c_ccg.c
new file mode 100644
index 000..587e3f8
--- /dev/null
+++ b/drivers/usb/typec/ucsi/ucsi_i2c_ccg.c
@@ -0,0 +1,591 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * UCSI I2C driver for Cypress CCGx Type-C controller
+ *
+ * Copyright (C) 2017-2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta 
+ *
+ * Some code borrowed from drivers/usb/typec/ucsi/ucsi_acpi.c
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "ucsi.h"
+
+struct ucsi_i2c_ccg {
+   struct device *dev;
+   struct ucsi *ucsi;
+   struct ucsi_ppm ppm;
+   struct i2c_client *client;
+   int irq;
+   bool wake_enabled;
+   unsigned char ver;
+};
+
+#define CCGX_I2C_RAB_DEVICE_MODE   0xU
+#define CCGX_I2C_RAB_BOOT_MODE_REASON  0x0001U
+#define CCGX_I2C_RAB_READ_SILICON_ID   0x0002U
+#define CCGX_I2C_RAB_INTR_REG  0x0006U
+#define CCGX_I2C_RAB_RESET 0x0008U
+#define CCGX_I2C_RAB_READ_ALL_VERSION  0x0010U
+#define CCGX_I2C_RAB_READ_ALL_VERSION_BOOTLOADER \
+   (CCGX_I2C_RAB_READ_ALL_VERSION + 0x00)
+#define CCGX_I2C_RAB_READ_ALL_VERSION_BOOTLOADER_BASE \
+   (CCGX_I2C_RAB_READ_ALL_VERSION_BOOTLOADER + 0)
+#define CCGX_I2C_RAB_READ_ALL_VERSION_BOOTLOADER_FW \
+   (CCGX_I2C_RAB_READ_ALL_VERSION_BOOTLOADER + 4)
+#define CCGX_I2C_RAB_READ_ALL_VERSION_APP \
+   (CCGX_I2C_RAB_READ_ALL_VERSION + 0x08)
+#define CCGX_I2C_RAB_READ_ALL_VERSION_APP_BASE \
+   (CCGX_I2C_RAB_READ_ALL_VERSION_APP + 0)
+#define CCGX_I2C_RAB_READ_ALL_VERSION_APP_FW \
+   (CCGX_I2C_RAB_READ_ALL_VERSION_APP + 4)
+#define CCGX_I2C_RAB_FW2_VERSION   0x0020U
+#define CCGX_I2C_RAB_PDPORT_ENABLE 0x002CU
+#define CCGX_I2C_RAB_UCSI_STATUS   0x0038U
+#define CCGX_I2C_RAB_UCSI_CONTROL  0x0039U
+#define CCGX_I2C_RAB_UCSI_CONTROL_STOP 0x2U
+#define CCGX_I2C_RAB_UCSI_CONTROL_START0x1U
+#define CCGX_I2C_RAB_HPI_VERSION   0x003CU
+#define CCGX_I2C_RAB_RESPONSE_REG  0x007EU
+#define CCGX_I2C_RAB_DM_CONTROL_1  0x1000U
+#define CCGX_I2C_RAB_WRITE_DATA_MEMORY_1   0x1800U
+#define CCGX_I2C_RAB_DM_CONTROL_2  0x2000U
+#define CCGX_I2C_RAB_WRITE_DATA_MEMORY_2   0x2800U
+#define CCGX_I2C_RAB_UCSI_DATA_BLOCK   0xf000U
+
+#define CCGX_I2C_RAB_RESPONSE_REG_RESET_COMPLETE   0x80
+
+static int ccg_read(struct ucsi_i2c_ccg *ui, u16 rab, u8 *data, u32 len)
+{
+   struct device *dev = ui->dev;
+   struct i2c_client *client = ui->client;
+   unsigned char buf[2];
+   struct i2c_msg msgs[] = {
+   {
+   .addr   = client->addr,
+   .flags  = 0x0,
+   .len= 0x2,
+   .buf= buf,
+   },
+   {
+   .addr   = client->addr,
+   .flags  = I2C_M_RD,
+   .buf= data,
+   },
+   };
+ 

[PATCH v2 1/2] i2c: buses: add i2c bus driver for NVIDIA GPU

2018-08-24 Thread Ajay Gupta
Latest NVIDIA GPU card has USB Type-C interface. There is a
Type-C controller which can be accessed over I2C.

This driver add I2C bus driver to communicate with Type-C controller.
I2C client driver will be part of USB Type-C UCSI driver.

Signed-off-by: Ajay Gupta 
---
Changes from v1 -> v2: None

 Documentation/i2c/busses/i2c-gpu |  18 ++
 MAINTAINERS  |   7 +
 drivers/i2c/busses/Kconfig   |   9 +
 drivers/i2c/busses/Makefile  |   1 +
 drivers/i2c/busses/i2c-gpu.c | 493 +++
 5 files changed, 528 insertions(+)
 create mode 100644 Documentation/i2c/busses/i2c-gpu
 create mode 100644 drivers/i2c/busses/i2c-gpu.c

diff --git a/Documentation/i2c/busses/i2c-gpu b/Documentation/i2c/busses/i2c-gpu
new file mode 100644
index 000..873ba34
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-gpu
@@ -0,0 +1,18 @@
+Kernel driver i2c-gpu
+
+Datasheet: not publicly available.
+
+Authors:
+   Ajay Gupta 
+
+Description
+---
+
+i2c-gpu is a driver for I2C controller included in NVIDIA Turing and later
+GPUs and it is used to communicate with Type-C controller on GPUs.
+
+If your 'lspci -v' listing shows something like the following,
+
+01:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device 1ad9 (rev a1)
+
+then this driver should support the I2C controller of your GPU.
diff --git a/MAINTAINERS b/MAINTAINERS
index b2fcd1c..e99f8a2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6796,6 +6796,13 @@ L:   linux-a...@vger.kernel.org
 S: Maintained
 F: drivers/i2c/i2c-core-acpi.c
 
+I2C CONTROLLER DRIVER FOR NVIDIA GPU
+M:     Ajay Gupta 
+L: linux-...@vger.kernel.org
+S: Maintained
+F: Documentation/i2c/busses/i2c-gpu
+F: drivers/i2c/busses/i2c-gpu.c
+
 I2C MUXES
 M: Peter Rosin 
 L: linux-...@vger.kernel.org
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 451d4ae..ff8b2d4 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -224,6 +224,15 @@ config I2C_NFORCE2_S4985
  This driver can also be built as a module.  If so, the module
  will be called i2c-nforce2-s4985.
 
+config I2C_GPU
+   tristate "NVIDIA GPU I2C controller"
+   depends on PCI
+   help
+ If you say yes to this option, support will be included for the
+ NVIDIA GPU I2C controller which is used to communicate with the GPU's
+ Type-C controller. This driver can also be built as a module called
+ i2c-gpu.ko.
+
 config I2C_SIS5595
tristate "SiS 5595"
depends on PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 18b26af..15d2894 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -140,5 +140,6 @@ obj-$(CONFIG_I2C_SIBYTE)+= i2c-sibyte.o
 obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o
 obj-$(CONFIG_SCx200_ACB)   += scx200_acb.o
 obj-$(CONFIG_I2C_FSI)  += i2c-fsi.o
+obj-$(CONFIG_I2C_GPU)  += i2c-gpu.o
 
 ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/busses/i2c-gpu.c b/drivers/i2c/busses/i2c-gpu.c
new file mode 100644
index 000..0fd2944
--- /dev/null
+++ b/drivers/i2c/busses/i2c-gpu.c
@@ -0,0 +1,493 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nvidia GPU I2C controller Driver
+ *
+ * Copyright (C) 2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta 
+ *
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* STATUS definitions  */
+#define STATUS_SUCCESS 0
+#define STATUS_UNSUCCESSFUL0x8000UL
+#define STATUS_TIMEOUT 0x8001UL
+#define STATUS_IO_DEVICE_ERROR 0x8002UL
+#define STATUS_IO_TIMEOUT  0x8004UL
+#define STATUS_IO_PREEMPTED0x8008UL
+
+/* Cypress Type-C controllers (CCGx) device */
+#define CCGX_I2C_DEV_ADDRESS   0x08
+
+/* I2C definitions */
+#define I2C_MST_CNTL   0x00
+#define I2C_MST_CNTL_GEN_START (1 << 0)
+#define I2C_MST_CNTL_GEN_STOP  (1 << 1)
+#define I2C_MST_CNTL_CMD_NONE  (0 << 2)
+#define I2C_MST_CNTL_CMD_READ  (1 << 2)
+#define I2C_MST_CNTL_CMD_WRITE (2 << 2)
+#define I2C_MST_CNTL_CMD_RESET (3 << 2)
+#define I2C_MST_CNTL_GEN_RAB   (1 << 4)
+#define I2C_MST_CNTL_BURST_SIZE_SHIFT  (6)
+#define I2C_MST_CNTL_GEN_NACK  (1 << 28)
+#define I2C_MST_CNTL_STATUS(3 << 29)
+#define I2C_MST_CNTL_STATUS_OKAY   (0 << 29)
+#define I2C_MST_CNTL_STATUS_NO_ACK (1 << 29)
+#define I2C_MST_CNTL_STATUS_TIMEOUT(2 << 29)
+#define I2C_MST_CNTL_STATUS_BUS_BUSY   (3 << 29)
+#define I2C_MST_CNTL_CYCLE_TRIGGER   

[PATCH v2 2/2] usb: typec: ucsi: add support for Cypress CCGx

2018-08-24 Thread Ajay Gupta
Latest NVIDIA GPU cards have a Cypress CCGx Type-C controller
over I2C interface.

This UCSI I2C driver uses I2C bus driver interface for communicating
with Type-C controller.

Signed-off-by: Ajay Gupta 
---
Changes from v1 -> v2:
Fixed identation in drivers/usb/typec/ucsi/Kconfig

 drivers/usb/typec/ucsi/Kconfig|  10 +
 drivers/usb/typec/ucsi/Makefile   |   2 +
 drivers/usb/typec/ucsi/ucsi_i2c_ccg.c | 591 ++
 3 files changed, 603 insertions(+)
 create mode 100644 drivers/usb/typec/ucsi/ucsi_i2c_ccg.c

diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig
index e36d6c7..0ce9d48 100644
--- a/drivers/usb/typec/ucsi/Kconfig
+++ b/drivers/usb/typec/ucsi/Kconfig
@@ -23,6 +23,16 @@ config TYPEC_UCSI
 
 if TYPEC_UCSI
 
+config UCSI_I2C_CCG
+   tristate "UCSI I2C Interface Driver for Cypress CCGx"
+   depends on I2C_GPU
+   help
+ This driver enables UCSI support on NVIDIA GPUs that expose a
+ Cypress CCGx Type-C controller over I2C interface.
+
+ To compile the driver as a module, choose M here: the module will be
+ called ucsi_i2c_ccg.ko.
+
 config UCSI_ACPI
tristate "UCSI ACPI Interface Driver"
depends on ACPI
diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile
index 7afbea5..4439482 100644
--- a/drivers/usb/typec/ucsi/Makefile
+++ b/drivers/usb/typec/ucsi/Makefile
@@ -8,3 +8,5 @@ typec_ucsi-y:= ucsi.o
 typec_ucsi-$(CONFIG_TRACING)   += trace.o
 
 obj-$(CONFIG_UCSI_ACPI)+= ucsi_acpi.o
+
+obj-$(CONFIG_UCSI_I2C_CCG) += ucsi_i2c_ccg.o
diff --git a/drivers/usb/typec/ucsi/ucsi_i2c_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_i2c_ccg.c
new file mode 100644
index 000..587e3f8
--- /dev/null
+++ b/drivers/usb/typec/ucsi/ucsi_i2c_ccg.c
@@ -0,0 +1,591 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * UCSI I2C driver for Cypress CCGx Type-C controller
+ *
+ * Copyright (C) 2017-2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta 
+ *
+ * Some code borrowed from drivers/usb/typec/ucsi/ucsi_acpi.c
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "ucsi.h"
+
+struct ucsi_i2c_ccg {
+   struct device *dev;
+   struct ucsi *ucsi;
+   struct ucsi_ppm ppm;
+   struct i2c_client *client;
+   int irq;
+   bool wake_enabled;
+   unsigned char ver;
+};
+
+#define CCGX_I2C_RAB_DEVICE_MODE   0xU
+#define CCGX_I2C_RAB_BOOT_MODE_REASON  0x0001U
+#define CCGX_I2C_RAB_READ_SILICON_ID   0x0002U
+#define CCGX_I2C_RAB_INTR_REG  0x0006U
+#define CCGX_I2C_RAB_RESET 0x0008U
+#define CCGX_I2C_RAB_READ_ALL_VERSION  0x0010U
+#define CCGX_I2C_RAB_READ_ALL_VERSION_BOOTLOADER \
+   (CCGX_I2C_RAB_READ_ALL_VERSION + 0x00)
+#define CCGX_I2C_RAB_READ_ALL_VERSION_BOOTLOADER_BASE \
+   (CCGX_I2C_RAB_READ_ALL_VERSION_BOOTLOADER + 0)
+#define CCGX_I2C_RAB_READ_ALL_VERSION_BOOTLOADER_FW \
+   (CCGX_I2C_RAB_READ_ALL_VERSION_BOOTLOADER + 4)
+#define CCGX_I2C_RAB_READ_ALL_VERSION_APP \
+   (CCGX_I2C_RAB_READ_ALL_VERSION + 0x08)
+#define CCGX_I2C_RAB_READ_ALL_VERSION_APP_BASE \
+   (CCGX_I2C_RAB_READ_ALL_VERSION_APP + 0)
+#define CCGX_I2C_RAB_READ_ALL_VERSION_APP_FW \
+   (CCGX_I2C_RAB_READ_ALL_VERSION_APP + 4)
+#define CCGX_I2C_RAB_FW2_VERSION   0x0020U
+#define CCGX_I2C_RAB_PDPORT_ENABLE 0x002CU
+#define CCGX_I2C_RAB_UCSI_STATUS   0x0038U
+#define CCGX_I2C_RAB_UCSI_CONTROL  0x0039U
+#define CCGX_I2C_RAB_UCSI_CONTROL_STOP 0x2U
+#define CCGX_I2C_RAB_UCSI_CONTROL_START0x1U
+#define CCGX_I2C_RAB_HPI_VERSION   0x003CU
+#define CCGX_I2C_RAB_RESPONSE_REG  0x007EU
+#define CCGX_I2C_RAB_DM_CONTROL_1  0x1000U
+#define CCGX_I2C_RAB_WRITE_DATA_MEMORY_1   0x1800U
+#define CCGX_I2C_RAB_DM_CONTROL_2  0x2000U
+#define CCGX_I2C_RAB_WRITE_DATA_MEMORY_2   0x2800U
+#define CCGX_I2C_RAB_UCSI_DATA_BLOCK   0xf000U
+
+#define CCGX_I2C_RAB_RESPONSE_REG_RESET_COMPLETE   0x80
+
+static int ccg_read(struct ucsi_i2c_ccg *ui, u16 rab, u8 *data, u32 len)
+{
+   struct device *dev = ui->dev;
+   struct i2c_client *client = ui->client;
+   unsigned char buf[2];
+   struct i2c_msg msgs[] = {
+   {
+   .addr   = client->addr,
+   .flags  = 0x0,
+   .len= 0x2,
+   .buf= buf,
+   },
+   {
+   .addr   = client->addr,
+   .flags  = I2C

RE: [PATCH v2 1/2] i2c: buses: add i2c bus driver for NVIDIA GPU

2018-08-29 Thread Ajay Gupta
Hi Andy,

> > Latest NVIDIA GPU card has USB Type-C interface. There is a
> > Type-C controller which can be accessed over I2C.
> >
> > This driver add I2C bus driver to communicate with Type-C controller.
> > I2C client driver will be part of USB Type-C UCSI driver.
> 
> >  drivers/i2c/busses/i2c-gpu.c | 493
> +++
> 
> Can we got more better name, which includes vendor and/or model of the I2C
> host?
Sure will change to i2c-nvidia-gpu.c

> > +/* STATUS definitions  */
> > +#define STATUS_SUCCESS 0
> > +#define STATUS_UNSUCCESSFUL0x8000UL
> > +#define STATUS_TIMEOUT 0x8001UL
> > +#define STATUS_IO_DEVICE_ERROR 0x8002UL
> > +#define STATUS_IO_TIMEOUT  0x8004UL
> > +#define STATUS_IO_PREEMPTED0x8008UL
> 
> Looks slightly different from my point of view, something like
> 
> /* Bit 31 shows error condition while LSB encodes the error code */
> STATUS_TIMEOUT BIT(0)
> ...
> STATUS_ERROR  BIT(31)
Will fix.

> > +   dev_dbg(dev, "%s: %p (I2C_MST_HYBRID_PADCTL) <- %08x", __func__,
> > +   (gdev->regs + I2C_MST_HYBRID_PADCTL), val);
> 
> Parens are redundant, __func__ is redundant.
Will fix.

> > +   dev_dbg(dev, "%s: %p (I2C_MST_I2C0_TIMING) <- %08x", __func__,
> > +   gdev->regs + I2C_MST_I2C0_TIMING, val);
> 
> Ditto. Check your debug messages, and perheps even drop some.
Will fix.

> > +static u32 i2c_check_status(struct gpu_i2c_dev *gdev)
> > +{
> 
> > +   while (time_is_after_jiffies(target)) {
> > +   }
> 
> For functions like this better to get in a form
> do {
> } while().
Ok, will fix.

> There is no guarantee that it runs even once in your case.
> 
> > +   dev_err(dev, "%si2c timeout", __func__);
> 
> No space?
Ok, will fix.
> 
> > +   val = readl(gdev->regs + I2C_MST_DATA);
> > +   switch (len) {
> > +   case 1:
> > +   data[0] = (val >> 0) & 0xff;
> > +   break;
> > +   case 2:
> > +   data[0] = (val >> 8) & 0xff;
> > +   data[1] = (val >> 0) & 0xff;
> > +   break;
> > +   case 3:
> > +   data[0] = (val >> 16) & 0xff;
> > +   data[1] = (val >> 8) & 0xff;
> > +   data[2] = (val >> 0) & 0xff;
> > +   break;
> > +   case 4:
> > +   data[0] = (val >> 24) & 0xff;
> > +   data[1] = (val >> 16) & 0xff;
> > +   data[2] = (val >> 8) & 0xff;
> > +   data[3] = (val >> 0) & 0xff;
> > +   break;
> 
> Redundant  & 0xff.
> We have get_unaligned*(), put_unaligned*() and many variations of
> cpu_to_Xe*() and Xe*_to_cpu().
Ok, will fix.
> 
> > +   u32 val = 0;
> 
> Redundant assignment.
Ok, will fix.
> 
> > +   val = addr << I2C_MST_ADDR_DAB;
> 
> > +   val = 0;
> 
> Ditto. What's wrong with assign value below directly?
> 
> > +   val |= I2C_MST_CNTL_GEN_START | I2C_MST_CNTL_CMD_NONE |
> > +   I2C_MST_CNTL_GEN_NACK;
> 
> > +   u32 val = 0;
> 
> Check your code for these kind of style mistakes.
> 
> > +/* gdev i2c adapter */
> 
> Pointless.
> 
> > +static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
> > +   struct i2c_msg *msgs, int num)
> > +{
> > +   struct gpu_i2c_dev *gdev = i2c_get_adapdata(adap);
> > +   struct device *dev = &gdev->pci_dev->dev;
> > +   int retry1b = 10;
> > +   u32 status;
> > +   int i, j;
> 
> > +   goto exit;
> > +exit_stop:
> > +   status = i2c_manual_stop(gdev);
> > +   if (status != STATUS_SUCCESS)
> > +   dev_err(dev, "i2c_manual_stop failed %x", status);
> > +exit:
> > +   mutex_unlock(&gdev->mutex);
> > +   return i;
> > +}
> 
> Ouch! Besides many small style issues and redundancy (like __LINE__),
> this function needs to be refactored to few smaller and readable ones.
Ok, will fix.
> 
> > +#define PCI_CLASS_SERIAL_UNKNOWN   0x0c80
> 
> > +/* pci driver */
> 
> Pointless.
Ok, will fix.
> 
> > +static const struct pci_device_id gpu_i2c_ids[] = {
> > +   { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
> > +   PCI_CLASS_SERIAL_UNKNOWN << 8, 0xff00},
> 
> Are you sure?!
Yes, we want to identify using vendor ID and class code. 
Currently there is no class code defined for UCSI device over PCI so using 
UNKNOWN.

> 
> > +   { },
> 
> Terminator line better w/o comma.
Ok, will fix.
> 
> > +};
> > +MODULE_DEVICE_TABLE(pci, gpu_i2c_ids);
> 
> > +static int gpu_i2c_probe(struct pci_dev *dev, const struct pci_device_id
> *id)
> > +{
> > +   struct gpu_i2c_dev *gdev;
> > +   int status;
> > +
> 
> > +   dev_info(&dev->dev,
> > +   "dev %p id %08x %08x sub %08x %08x class %08x %08x\n",
> > +   dev, id->vendor, id->device, id->subvendor, id->subdevice,
> > +   id->class, id->class_mask);
> 
> Useless. We have PCI core printed this information out sever

RE: [v2,1/2] i2c: buses: add i2c bus driver for NVIDIA GPU

2018-08-29 Thread Ajay Gupta
Hi Thierry,

> > Latest NVIDIA GPU card has USB Type-C interface. There is a Type-C
> > controller which can be accessed over I2C.
> >
> > This driver add I2C bus driver to communicate with Type-C controller.
> > I2C client driver will be part of USB Type-C UCSI driver.
> >
> > Signed-off-by: Ajay Gupta 
> > ---
> > Changes from v1 -> v2: None
> >
> >  Documentation/i2c/busses/i2c-gpu |  18 ++
> >  MAINTAINERS  |   7 +
> >  drivers/i2c/busses/Kconfig   |   9 +
> >  drivers/i2c/busses/Makefile  |   1 +
> >  drivers/i2c/busses/i2c-gpu.c | 493
> +++
> >  5 files changed, 528 insertions(+)
> >  create mode 100644 Documentation/i2c/busses/i2c-gpu  create mode
> > 100644 drivers/i2c/busses/i2c-gpu.c
> 
> Hi Ajay,
> 
> I think this looks pretty good. A couple of minor, mostly nit-picky, comments
> below.
> 
> >
> > diff --git a/Documentation/i2c/busses/i2c-gpu
> > b/Documentation/i2c/busses/i2c-gpu
> > new file mode 100644
> > index 000..873ba34
> > --- /dev/null
> > +++ b/Documentation/i2c/busses/i2c-gpu
> 
> I think this is too generic. Maybe use something like i2c-nvidia-gpu here and
> everywhere else, to make it explicit that this is for NVIDIA GPUs rather than
> GPUs in general.
ok

> > @@ -0,0 +1,18 @@
> > +Kernel driver i2c-gpu
> > +
> > +Datasheet: not publicly available.
> > +
> > +Authors:
> > +   Ajay Gupta 
> > +
> > +Description
> > +---
> > +
> > +i2c-gpu is a driver for I2C controller included in NVIDIA Turing and
> > +later GPUs and it is used to communicate with Type-C controller on GPUs.
> > +
> > +If your 'lspci -v' listing shows something like the following,
> > +
> > +01:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device 1ad9
> > +(rev a1)
> > +
> > +then this driver should support the I2C controller of your GPU.
> > diff --git a/MAINTAINERS b/MAINTAINERS index b2fcd1c..e99f8a2 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -6796,6 +6796,13 @@ L:   linux-a...@vger.kernel.org
> >  S: Maintained
> >  F: drivers/i2c/i2c-core-acpi.c
> >
> > +I2C CONTROLLER DRIVER FOR NVIDIA GPU
> > +M: Ajay Gupta 
> > +L: linux-...@vger.kernel.org
> > +S: Maintained
> > +F: Documentation/i2c/busses/i2c-gpu
> > +F: drivers/i2c/busses/i2c-gpu.c
> > +
> >  I2C MUXES
> >  M: Peter Rosin 
> >  L: linux-...@vger.kernel.org
> > diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> > index 451d4ae..ff8b2d4 100644
> > --- a/drivers/i2c/busses/Kconfig
> > +++ b/drivers/i2c/busses/Kconfig
> > @@ -224,6 +224,15 @@ config I2C_NFORCE2_S4985
> >   This driver can also be built as a module.  If so, the module
> >   will be called i2c-nforce2-s4985.
> >
> > +config I2C_GPU
> > +   tristate "NVIDIA GPU I2C controller"
> > +   depends on PCI
> > +   help
> > + If you say yes to this option, support will be included for the
> > + NVIDIA GPU I2C controller which is used to communicate with the
> GPU's
> > + Type-C controller. This driver can also be built as a module called
> > + i2c-gpu.ko.
> > +
> >  config I2C_SIS5595
> > tristate "SiS 5595"
> > depends on PCI
> > diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> > index 18b26af..15d2894 100644
> > --- a/drivers/i2c/busses/Makefile
> > +++ b/drivers/i2c/busses/Makefile
> > @@ -140,5 +140,6 @@ obj-$(CONFIG_I2C_SIBYTE)+= i2c-sibyte.o
> >  obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o
> >  obj-$(CONFIG_SCx200_ACB)   += scx200_acb.o
> >  obj-$(CONFIG_I2C_FSI)  += i2c-fsi.o
> > +obj-$(CONFIG_I2C_GPU)  += i2c-gpu.o
> >
> >  ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG diff --git
> > a/drivers/i2c/busses/i2c-gpu.c b/drivers/i2c/busses/i2c-gpu.c new file
> > mode 100644 index 000..0fd2944
> > --- /dev/null
> > +++ b/drivers/i2c/busses/i2c-gpu.c
> > @@ -0,0 +1,493 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Nvidia GPU I2C controller Driver
> > + *
> > + * Copyright (C) 2018 NVIDIA Corporation. All rights reserved.
> > + * Author: Ajay Gupta 
> > + *
> > + */
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +
> > +/* STATUS definitions  

RE: [PATCH v2 2/2] usb: typec: ucsi: add support for Cypress CCGx

2018-08-29 Thread Ajay Gupta
Hi Heikki,

> On Fri, Aug 24, 2018 at 02:33:36PM -0700, Ajay Gupta wrote:
> > Latest NVIDIA GPU cards have a Cypress CCGx Type-C controller
> > over I2C interface.
> >
> > This UCSI I2C driver uses I2C bus driver interface for communicating
> > with Type-C controller.
> 
> Cool. The patch looks fairly good to me, but I put a few comments
> below.
Thanks for review.

> 
> > Signed-off-by: Ajay Gupta 
> > ---
> > Changes from v1 -> v2:
> > Fixed identation in drivers/usb/typec/ucsi/Kconfig
> >
> >  drivers/usb/typec/ucsi/Kconfig|  10 +
> >  drivers/usb/typec/ucsi/Makefile   |   2 +
> >  drivers/usb/typec/ucsi/ucsi_i2c_ccg.c | 591
> ++
> 
> CCGx controllers support also SPI and UART AFAIK. Though, I'm not sure
> how commonly they are used (I would expect I2C to be the most common
> with these controllers), the driver should ultimately work with both
> of those busses as well.
> 
> To avoid confusion, and potential driver duplicates in the future,
> just name the driver ucsi_ccg.c for now, and also s/i2c_ccg/ccg/
> everything in the driver (except the i2c_driver structure of course).
Sure.


> >  3 files changed, 603 insertions(+)
> >  create mode 100644 drivers/usb/typec/ucsi/ucsi_i2c_ccg.c
> >
> > diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig
> > index e36d6c7..0ce9d48 100644
> > --- a/drivers/usb/typec/ucsi/Kconfig
> > +++ b/drivers/usb/typec/ucsi/Kconfig
> > @@ -23,6 +23,16 @@ config TYPEC_UCSI
> >
> >  if TYPEC_UCSI
> >
> > +config UCSI_I2C_CCG
> > +   tristate "UCSI I2C Interface Driver for Cypress CCGx"
> > +   depends on I2C_GPU
> 
> Why does it need to depend only on your I2C controller?
> 
> I think that should be just "depends on I2C".
ok
 
> > +   help
> > + This driver enables UCSI support on NVIDIA GPUs that expose a
> > + Cypress CCGx Type-C controller over I2C interface.
> > +
> > + To compile the driver as a module, choose M here: the module will
> be
> > + called ucsi_i2c_ccg.ko.
> > +
> >  config UCSI_ACPI
> > tristate "UCSI ACPI Interface Driver"
> > depends on ACPI
> > diff --git a/drivers/usb/typec/ucsi/Makefile
> b/drivers/usb/typec/ucsi/Makefile
> > index 7afbea5..4439482 100644
> > --- a/drivers/usb/typec/ucsi/Makefile
> > +++ b/drivers/usb/typec/ucsi/Makefile
> > @@ -8,3 +8,5 @@ typec_ucsi-y:= ucsi.o
> >  typec_ucsi-$(CONFIG_TRACING)   += trace.o
> >
> >  obj-$(CONFIG_UCSI_ACPI)+= ucsi_acpi.o
> > +
> > +obj-$(CONFIG_UCSI_I2C_CCG) += ucsi_i2c_ccg.o
> > diff --git a/drivers/usb/typec/ucsi/ucsi_i2c_ccg.c
> b/drivers/usb/typec/ucsi/ucsi_i2c_ccg.c
> > new file mode 100644
> > index 000..587e3f8
> > --- /dev/null
> > +++ b/drivers/usb/typec/ucsi/ucsi_i2c_ccg.c
> > @@ -0,0 +1,591 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * UCSI I2C driver for Cypress CCGx Type-C controller
> > + *
> > + * Copyright (C) 2017-2018 NVIDIA Corporation. All rights reserved.
> > + * Author: Ajay Gupta 
> > + *
> > + * Some code borrowed from drivers/usb/typec/ucsi/ucsi_acpi.c
> > + */
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include "ucsi.h"
> > +
> > +struct ucsi_i2c_ccg {
> > +   struct device *dev;
> > +   struct ucsi *ucsi;
> > +   struct ucsi_ppm ppm;
> > +   struct i2c_client *client;
> > +   int irq;
> > +   bool wake_enabled;
> > +   unsigned char ver;
> > +};
> > +
> > +#define CCGX_I2C_RAB_DEVICE_MODE   0xU
> > +#define CCGX_I2C_RAB_BOOT_MODE_REASON
>   0x0001U
> > +#define CCGX_I2C_RAB_READ_SILICON_ID   0x0002U
> > +#define CCGX_I2C_RAB_INTR_REG  0x0006U
> > +#define CCGX_I2C_RAB_RESET 0x0008U
> > +#define CCGX_I2C_RAB_READ_ALL_VERSION  0x0010U
> > +#define CCGX_I2C_RAB_READ_ALL_VERSION_BOOTLOADER \
> > +   (CCGX_I2C_RAB_READ_ALL_VERSION + 0x00)
> > +#define CCGX_I2C_RAB_READ_ALL_VERSION_BOOTLOADER_BASE \
> > +   (CCGX_I2C_RAB_READ_ALL_VERSION_BOOTLOADER
> + 0)
> > +#define CCGX_I2C_RAB_READ_ALL_VERSION_BOOTLOADER_FW \
> > +   (CCGX_I2C_RAB_READ_ALL_VERSION_BOOTLOADER
> + 4)
> > +#define CCGX_I2C_RAB_READ_ALL_VERSION_APP \
> > +   

RE: [PATCH v3 1/2] i2c: buses: add i2c bus driver for NVIDIA GPU

2018-08-30 Thread Ajay Gupta
Hi Andy,
> > Latest NVIDIA GPU card has USB Type-C interface. There is a Type-C
> > controller which can be accessed over I2C.
> >
> > This driver adds I2C bus driver to communicate with Type-C controller.
> > I2C client driver will be part of USB Type-C UCSI driver.
> >
> 
> Some small comments below, after addressing them
> 
> Reviewed-by: Andy Shevchenko 
> 
> > Signed-off-by: Ajay Gupta 
> > ---
> > Changes from v1 -> v2
> > None
> > Changes from v2 -> v3
> > Fixed review comments from Andy and Thierry
> > Rename i2c-gpu.c -> i2c-nvidia-gpu.c
> >
> >  Documentation/i2c/busses/i2c-nvidia-gpu |  18 ++
> >  MAINTAINERS |   7 +
> >  drivers/i2c/busses/Kconfig  |   9 +
> >  drivers/i2c/busses/Makefile |   1 +
> >  drivers/i2c/busses/i2c-nvidia-gpu.c | 389
> 
> >  5 files changed, 424 insertions(+)
> >  create mode 100644 Documentation/i2c/busses/i2c-nvidia-gpu
> >  create mode 100644 drivers/i2c/busses/i2c-nvidia-gpu.c
> >
> > diff --git a/Documentation/i2c/busses/i2c-nvidia-gpu
> > b/Documentation/i2c/busses/i2c-nvidia-gpu
> > new file mode 100644
> > index 000..31884d2
> > --- /dev/null
> > +++ b/Documentation/i2c/busses/i2c-nvidia-gpu
> > @@ -0,0 +1,18 @@
> > +Kernel driver i2c-nvidia-gpu
> > +
> > +Datasheet: not publicly available.
> > +
> > +Authors:
> > +   Ajay Gupta 
> > +
> > +Description
> > +---
> > +
> > +i2c-nvidia-gpu is a driver for I2C controller included in NVIDIA
> > +Turing and later GPUs and it is used to communicate with Type-C controller
> on GPUs.
> > +
> > +If your 'lspci -v' listing shows something like the following,
> > +
> > +01:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device 1ad9
> > +(rev a1)
> > +
> > +then this driver should support the I2C controller of your GPU.
> > diff --git a/MAINTAINERS b/MAINTAINERS index 9ad052a..2d1c5a1 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -6797,6 +6797,13 @@ L:   linux-a...@vger.kernel.org
> >  S: Maintained
> >  F: drivers/i2c/i2c-core-acpi.c
> >
> > +I2C CONTROLLER DRIVER FOR NVIDIA GPU
> > +M: Ajay Gupta 
> > +L: linux-...@vger.kernel.org
> > +S: Maintained
> > +F: Documentation/i2c/busses/i2c-nvidia-gpu
> > +F: drivers/i2c/busses/i2c-nvidia-gpu.c
> > +
> >  I2C MUXES
> >  M: Peter Rosin 
> >  L: linux-...@vger.kernel.org
> > diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> > index 451d4ae..eed827b 100644
> > --- a/drivers/i2c/busses/Kconfig
> > +++ b/drivers/i2c/busses/Kconfig
> > @@ -224,6 +224,15 @@ config I2C_NFORCE2_S4985
> >   This driver can also be built as a module.  If so, the module
> >   will be called i2c-nforce2-s4985.
> >
> > +config I2C_NVIDIA_GPU
> > +   tristate "NVIDIA GPU I2C controller"
> > +   depends on PCI
> > +   help
> > + If you say yes to this option, support will be included for the
> > + NVIDIA GPU I2C controller which is used to communicate with the
> GPU's
> > + Type-C controller. This driver can also be built as a module 
> > called
> > + i2c-nvidia-gpu.
> > +
> >  config I2C_SIS5595
> > tristate "SiS 5595"
> > depends on PCI
> > diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> > index 18b26af..d499813 100644
> > --- a/drivers/i2c/busses/Makefile
> > +++ b/drivers/i2c/busses/Makefile
> > @@ -140,5 +140,6 @@ obj-$(CONFIG_I2C_SIBYTE)+= i2c-sibyte.o
> >  obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o
> >  obj-$(CONFIG_SCx200_ACB)   += scx200_acb.o
> >  obj-$(CONFIG_I2C_FSI)  += i2c-fsi.o
> > +obj-$(CONFIG_I2C_NVIDIA_GPU)   += i2c-nvidia-gpu.o
> >
> >  ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG diff --git
> > a/drivers/i2c/busses/i2c-nvidia-gpu.c
> > b/drivers/i2c/busses/i2c-nvidia-gpu.c
> > new file mode 100644
> > index 000..fa01187
> > --- /dev/null
> > +++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
> > @@ -0,0 +1,389 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Nvidia GPU I2C controller Driver
> > + *
> > + * Copyright (C) 2018 NVIDIA Corporation. All rights reserved.
> > + * Author: Ajay Gupta 
> 
> > + *
> 
&g

RE: [PATCH v3 2/2] usb: typec: ucsi: add support for Cypress CCGx

2018-08-30 Thread Ajay Gupta
"ucsi_ccg_ack_interrupt() err %d\n",
> > + err);
> > +
> > +   return 0;
> > +}
> > +
> > +static int ucsi_ccg_cmd(struct ucsi_ppm *ppm, struct ucsi_control
> > +*ctrl) {
> 
> > +   struct ucsi_ccg *uc = container_of(ppm,
> > +   struct ucsi_ccg, ppm);
> 
> Why not one line?
sure
> 
> > +   int err = 0;
> > +
> > +   ppm->data->ctrl.raw_cmd = ctrl->raw_cmd;
> > +   err = ucsi_ccg_send_data(uc);
> > +
> > +   return err;
> > +}
> > +
> > +static irqreturn_t ccg_irq_handler(int irq, void *data) {
> > +   struct ucsi_ccg *uc = data;
> > +
> > +   ucsi_notify(uc->ucsi);
> > +
> > +   return IRQ_HANDLED;
> > +}
> > +
> 
> > +static int ucsi_ccg_probe(struct i2c_client *client,
> > + const struct i2c_device_id *id)
> 
> One line?
> 
> > +{
> > +   struct device *dev = &client->dev;
> > +   struct ucsi_ccg *uc;
> > +   int status;
> > +
> > +   uc = devm_kzalloc(dev, sizeof(*uc), GFP_KERNEL);
> > +   if (!uc)
> > +   return -ENOMEM;
> > +
> > +   uc->ppm.data = devm_kzalloc(dev, sizeof(struct ucsi_data),
> GFP_KERNEL);
> > +   if (!uc->ppm.data)
> > +   return -ENOMEM;
> > +
> > +   uc->ppm.cmd = ucsi_ccg_cmd;
> > +   uc->ppm.sync = ucsi_ccg_sync;
> > +   uc->dev = dev;
> > +   uc->client = client;
> > +
> > +   /* reset ccg device and initialize ucsi */
> > +   status = ucsi_ccg_init(uc);
> > +   if (status < 0) {
> > +   dev_err(uc->dev, "ucsi_ccg_init failed - %d\n", status);
> > +   return status;
> > +   }
> > +
> > +   uc->irq = client->irq;
> > +
> 
> > +   status = devm_request_threaded_irq(dev, uc->irq, NULL,
> ccg_irq_handler,
> > +  IRQF_ONESHOT |
> > + IRQF_TRIGGER_HIGH,
> 
> ONESHORT can be dropped here (it's set based on condition when irq handler
> NULL and threadirq is not).
Below error is seen if I drop ONESHOT

"genirq: Threaded irq requested with handler=NULL and !ONESHOT for irq 129"

> 
> > +  dev_name(dev), uc);
> > +   if (status < 0) {
> > +   dev_err(uc->dev, "request_threaded_irq failed - %d\n", 
> > status);
> > +   return status;
> > +   }
> > +
> > +   uc->ucsi = ucsi_register_ppm(dev, &uc->ppm);
> > +   if (IS_ERR(uc->ucsi)) {
> > +   dev_err(uc->dev, "ucsi_register_ppm failed\n");
> > +   return PTR_ERR(uc->ucsi);
> > +   }
> > +
> > +   i2c_set_clientdata(client, uc);
> > +   return 0;
> > +}
> > +
> > +static int ucsi_ccg_remove(struct i2c_client *client) {
> > +   struct ucsi_ccg *uc = i2c_get_clientdata(client);
> > +
> > +   ucsi_unregister_ppm(uc->ucsi);
> > +
> > +   return 0;
> > +}
> > +
> > +static const struct i2c_device_id ucsi_ccg_device_id[] = {
> > +   {"ccgx-ucsi", 0},
> 
> > +   {},
> 
> Terminator line better without comma.
Ok

Thanks
Ajay

--
nvpublic
--
> 
> > +};
> > +MODULE_DEVICE_TABLE(i2c, ucsi_ccg_device_id);
> > +
> > +static struct i2c_driver ucsi_ccg_driver = {
> > +   .driver = {
> > +   .name = "ucsi_ccg",
> > +   },
> > +   .probe = ucsi_ccg_probe,
> > +   .remove = ucsi_ccg_remove,
> > +   .id_table = ucsi_ccg_device_id, };
> > +
> > +module_i2c_driver(ucsi_ccg_driver);
> > +
> > +MODULE_AUTHOR("Ajay Gupta ");
> > +MODULE_DESCRIPTION("UCSI driver for Cypress CCGx Type-C controller");
> > +MODULE_LICENSE("GPL v2");
> > --
> > 2.7.4
> >
> 
> 
> --
> With Best Regards,
> Andy Shevchenko


[PATCH v4 1/2] i2c: buses: add i2c bus driver for NVIDIA GPU

2018-08-30 Thread Ajay Gupta
Latest NVIDIA GPU card has USB Type-C interface. There is a
Type-C controller which can be accessed over I2C.

This driver adds I2C bus driver to communicate with Type-C controller.
I2C client driver will be part of USB Type-C UCSI driver.

Signed-off-by: Ajay Gupta 
---
Changes from v1 -> v2
None
Changes from v2 -> v3
Fixed review comments from Andy and Thierry
Rename i2c-gpu.c -> i2c-nvidia-gpu.c
Changes from v3 -> v4
Fixed review comments from Andy

 Documentation/i2c/busses/i2c-nvidia-gpu |  18 ++
 MAINTAINERS |   7 +
 drivers/i2c/busses/Kconfig  |   9 +
 drivers/i2c/busses/Makefile |   1 +
 drivers/i2c/busses/i2c-nvidia-gpu.c | 398 
 5 files changed, 433 insertions(+)
 create mode 100644 Documentation/i2c/busses/i2c-nvidia-gpu
 create mode 100644 drivers/i2c/busses/i2c-nvidia-gpu.c

diff --git a/Documentation/i2c/busses/i2c-nvidia-gpu 
b/Documentation/i2c/busses/i2c-nvidia-gpu
new file mode 100644
index 000..31884d2
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-nvidia-gpu
@@ -0,0 +1,18 @@
+Kernel driver i2c-nvidia-gpu
+
+Datasheet: not publicly available.
+
+Authors:
+   Ajay Gupta 
+
+Description
+---
+
+i2c-nvidia-gpu is a driver for I2C controller included in NVIDIA Turing
+and later GPUs and it is used to communicate with Type-C controller on GPUs.
+
+If your 'lspci -v' listing shows something like the following,
+
+01:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device 1ad9 (rev a1)
+
+then this driver should support the I2C controller of your GPU.
diff --git a/MAINTAINERS b/MAINTAINERS
index 9ad052a..2d1c5a1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6797,6 +6797,13 @@ L:   linux-a...@vger.kernel.org
 S: Maintained
 F: drivers/i2c/i2c-core-acpi.c
 
+I2C CONTROLLER DRIVER FOR NVIDIA GPU
+M: Ajay Gupta 
+L: linux-...@vger.kernel.org
+S: Maintained
+F: Documentation/i2c/busses/i2c-nvidia-gpu
+F: drivers/i2c/busses/i2c-nvidia-gpu.c
+
 I2C MUXES
 M: Peter Rosin 
 L: linux-...@vger.kernel.org
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 451d4ae..eed827b 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -224,6 +224,15 @@ config I2C_NFORCE2_S4985
  This driver can also be built as a module.  If so, the module
  will be called i2c-nforce2-s4985.
 
+config I2C_NVIDIA_GPU
+   tristate "NVIDIA GPU I2C controller"
+   depends on PCI
+   help
+ If you say yes to this option, support will be included for the
+ NVIDIA GPU I2C controller which is used to communicate with the GPU's
+ Type-C controller. This driver can also be built as a module called
+ i2c-nvidia-gpu.
+
 config I2C_SIS5595
tristate "SiS 5595"
depends on PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 18b26af..d499813 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -140,5 +140,6 @@ obj-$(CONFIG_I2C_SIBYTE)+= i2c-sibyte.o
 obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o
 obj-$(CONFIG_SCx200_ACB)   += scx200_acb.o
 obj-$(CONFIG_I2C_FSI)  += i2c-fsi.o
+obj-$(CONFIG_I2C_NVIDIA_GPU)   += i2c-nvidia-gpu.o
 
 ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
new file mode 100644
index 000..51b8712
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -0,0 +1,398 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nvidia GPU I2C controller Driver
+ *
+ * Copyright (C) 2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta 
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* I2C definitions */
+#define I2C_MST_CNTL   0x00
+#define I2C_MST_CNTL_GEN_START BIT(0)
+#define I2C_MST_CNTL_GEN_STOP  BIT(1)
+#define I2C_MST_CNTL_CMD_NONE  (0 << 2)
+#define I2C_MST_CNTL_CMD_READ  (1 << 2)
+#define I2C_MST_CNTL_CMD_WRITE (2 << 2)
+#define I2C_MST_CNTL_GEN_RAB   BIT(4)
+#define I2C_MST_CNTL_BURST_SIZE_SHIFT  6
+#define I2C_MST_CNTL_GEN_NACK  BIT(28)
+#define I2C_MST_CNTL_STATUSGENMASK(30, 29)
+#define I2C_MST_CNTL_STATUS_OKAY   (0 << 29)
+#define I2C_MST_CNTL_STATUS_NO_ACK (1 << 29)
+#define I2C_MST_CNTL_STATUS_TIMEOUT(2 << 29)
+#define I2C_MST_CNTL_STATUS_BUS_BUSY   (3 << 29)
+#define I2C_MST_CNTL_CYCLE_TRIGGER BIT(31)
+
+#define I2C_MST_ADDR   0x04
+#define I2C_MST_ADDR_DAB   0
+
+#define I2C_MST_I2C0_TIMING0x08
+#define I2C_MST_

[PATCH v4 2/2] usb: typec: ucsi: add support for Cypress CCGx

2018-08-30 Thread Ajay Gupta
Latest NVIDIA GPU cards have a Cypress CCGx Type-C controller
over I2C interface.

This UCSI I2C driver uses I2C bus driver interface for communicating
with Type-C controller.

Signed-off-by: Ajay Gupta 
---
Changes from v1 -> v2
Fixed identation in drivers/usb/typec/ucsi/Kconfig
Changes from v2 -> v3
Fixed most of comments from Heikki
Rename ucsi_i2c_ccg.c -> ucsi_ccg.c
Changes from v3 -> v4
Fixed comments from Andy

 drivers/usb/typec/ucsi/Kconfig|  10 +
 drivers/usb/typec/ucsi/Makefile   |   2 +
 drivers/usb/typec/ucsi/ucsi_ccg.c | 393 ++
 3 files changed, 405 insertions(+)
 create mode 100644 drivers/usb/typec/ucsi/ucsi_ccg.c

diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig
index e36d6c7..7811888 100644
--- a/drivers/usb/typec/ucsi/Kconfig
+++ b/drivers/usb/typec/ucsi/Kconfig
@@ -23,6 +23,16 @@ config TYPEC_UCSI
 
 if TYPEC_UCSI
 
+config UCSI_CCG
+   tristate "UCSI Interface Driver for Cypress CCGx"
+   depends on I2C
+   help
+ This driver enables UCSI support on platforms that expose a
+ Cypress CCGx Type-C controller over I2C interface.
+
+ To compile the driver as a module, choose M here: the module will be
+ called ucsi_ccg.
+
 config UCSI_ACPI
tristate "UCSI ACPI Interface Driver"
depends on ACPI
diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile
index 7afbea5..2f4900b 100644
--- a/drivers/usb/typec/ucsi/Makefile
+++ b/drivers/usb/typec/ucsi/Makefile
@@ -8,3 +8,5 @@ typec_ucsi-y:= ucsi.o
 typec_ucsi-$(CONFIG_TRACING)   += trace.o
 
 obj-$(CONFIG_UCSI_ACPI)+= ucsi_acpi.o
+
+obj-$(CONFIG_UCSI_CCG) += ucsi_ccg.o
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
new file mode 100644
index 000..68efefa
--- /dev/null
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -0,0 +1,393 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * UCSI driver for Cypress CCGx Type-C controller
+ *
+ * Copyright (C) 2017-2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta 
+ *
+ * Some code borrowed from drivers/usb/typec/ucsi/ucsi_acpi.c
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "ucsi.h"
+
+struct ucsi_ccg {
+   struct device *dev;
+   struct ucsi *ucsi;
+   struct ucsi_ppm ppm;
+   struct i2c_client *client;
+   int irq;
+};
+
+#define CCGX_I2C_RAB_DEVICE_MODE   0x00
+#define CCGX_I2C_RAB_READ_SILICON_ID   0x2
+#define CCGX_I2C_RAB_INTR_REG  0x06
+#define CCGX_I2C_RAB_FW1_VERSION   0x28
+#define CCGX_I2C_RAB_FW2_VERSION   0x20
+#define CCGX_I2C_RAB_UCSI_CONTROL  0x39
+#define CCGX_I2C_RAB_UCSI_CONTROL_STARTBIT(0)
+#define CCGX_I2C_RAB_UCSI_CONTROL_STOP BIT(1)
+#define CCGX_I2C_RAB_RESPONSE_REG  0x7E
+#define CCGX_I2C_RAB_UCSI_DATA_BLOCK   0xf000
+
+static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
+{
+   struct device *dev = uc->dev;
+   struct i2c_client *client = uc->client;
+   unsigned char buf[2];
+   struct i2c_msg msgs[] = {
+   {
+   .addr   = client->addr,
+   .flags  = 0x0,
+   .len= 0x2,
+   .buf= buf,
+   },
+   {
+   .addr   = client->addr,
+   .flags  = I2C_M_RD,
+   .buf= data,
+   },
+   };
+   u32 rlen, rem_len = len;
+   int err = -EIO;
+
+   while (rem_len > 0) {
+   msgs[1].buf = &data[len - rem_len];
+   rlen = min_t(u16, rem_len, 4);
+   msgs[1].len = rlen;
+   put_unaligned_le16(rab, buf);
+   err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+   if (err == ARRAY_SIZE(msgs)) {
+   err = 0;
+   } else if (err >= 0) {
+   dev_err(dev, "i2c_transfer failed, err %d\n", err);
+   return -EIO;
+   }
+   rab += rlen;
+   rem_len -= rlen;
+   }
+
+   return err;
+}
+
+static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
+{
+   struct device *dev = uc->dev;
+   struct i2c_client *client = uc->client;
+   unsigned char buf[2];
+   struct i2c_msg msgs[] = {
+   {
+   .addr   = client->addr,
+   .flags  = 0x0,
+   .len= 0x2,
+   .buf= buf,
+   },
+   {
+   .addr   = clien

RE: [PATCH v4 1/2] i2c: buses: add i2c bus driver for NVIDIA GPU

2018-08-31 Thread Ajay Gupta
Hi Andy,
> > Latest NVIDIA GPU card has USB Type-C interface. There is a Type-C
> > controller which can be accessed over I2C.
> >
> > This driver adds I2C bus driver to communicate with Type-C controller.
> > I2C client driver will be part of USB Type-C UCSI driver.
> 
> Thanks for an update, my comments below.
Thanks for reviewing.
 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> 
> + blank line.
Ok. 
I could not find kernel documentation which requires this blank line.
Can you please point me to it?
 
> > +#include 
> 
> > +struct gpu_i2c_dev {
> > +   struct device *dev;
> > +   void __iomem *regs;
> > +   struct i2c_adapter adapter;
> > +   struct i2c_client *client;
> > +   struct mutex mutex; /* to sync read/write */
> > +   bool do_start;
> > +};
> 
> > +static int i2c_check_status(struct gpu_i2c_dev *i2cd) {
> > +   unsigned long target = jiffies + msecs_to_jiffies(1000);
> > +   u32 val;
> > +
> > +   do {
> > +   val = readl(i2cd->regs + I2C_MST_CNTL);
> 
> > +   if ((val & I2C_MST_CNTL_CYCLE_TRIGGER) !=
> > +   I2C_MST_CNTL_CYCLE_TRIGGER)
> 
> Part after != redundant since it's one bit.
> But I'm fine with current as well.
Ok, will fix.
> 
> > +   break;
> > +   if ((val & I2C_MST_CNTL_STATUS) !=
> > +   I2C_MST_CNTL_STATUS_BUS_BUSY)
> > +   break;
> > +   usleep_range(1000, 2000);
> > +   } while (time_is_after_jiffies(target));
> 
> > +
> 
> Redundant.
Ok, I will remove it but I didn't understand why its redundant?
I thought adding extra line would be more readable.
 
> > +   if (time_is_before_jiffies(target))
> > +   return -EIO;
> > +
> > +   val = readl(i2cd->regs + I2C_MST_CNTL);
> > +   switch (val & I2C_MST_CNTL_STATUS) {
> > +   case I2C_MST_CNTL_STATUS_OKAY:
> > +   return 0;
> > +   case I2C_MST_CNTL_STATUS_NO_ACK:
> > +   return -EIO;
> > +   case I2C_MST_CNTL_STATUS_TIMEOUT:
> > +   return -ETIME;
> > +   case I2C_MST_CNTL_STATUS_BUS_BUSY:
> > +   return -EBUSY;
> > +   default:
> 
> > +   break;
> 
> return 0; ?
Ok, will fix.
> 
> > +   }
> 
> > +   return 0;
> 
> See above.
Ok
> 
> > +}
> 
> > +static int i2c_write(struct gpu_i2c_dev *i2cd, u8 data) {
> > +   u32 val;
> > +
> > +   writel(data, i2cd->regs + I2C_MST_DATA);
> > +
> > +   val = I2C_MST_CNTL_CMD_WRITE | (1 <<
> I2C_MST_CNTL_BURST_SIZE_SHIFT) |
> > +   I2C_MST_CNTL_GEN_NACK;
> 
> > +   val &= ~(I2C_MST_CNTL_GEN_START | I2C_MST_CNTL_GEN_STOP
> > +   | I2C_MST_CNTL_GEN_RAB);
> 
> "|" should be on previous line to follow common style in this module.
The "|" here is to clear the bit together.  [val &= ~(X | Y | Z)]
Style in this module is still followed. Please see first line which does "|" to 
val.

> > +   writel(val, i2cd->regs + I2C_MST_CNTL);
> > +
> > +   return i2c_check_status(i2cd); }
> > +
> > +static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
> > +  struct i2c_msg *msgs, int num) {
> > +   struct gpu_i2c_dev *i2cd = i2c_get_adapdata(adap);
> > +   struct device *dev = i2cd->dev;
> > +   int status;
> > +   int i, j;
> 
> > +stop:
> > +   status = i2c_stop(i2cd);
> > +   if (status < 0)
> > +   dev_err(dev, "i2c_stop error %x", status);
> > +unlock:
> > +   mutex_unlock(&i2cd->mutex);
> 
> > +   return i;
> 
> Shouldn't it return status in case of error?
Thanks, will fix.
 
> > +}
> 
> > +/*
> > + * This driver is for the Nvidia GPU cards with USB Type-C interface.
> > + * We want to identify the cards using vendor ID and class code.
> > + * Currently there is no class code defined for UCSI device over PCI
> > + * so using UNKNOWN.
> > + */
> 
> So, I didn't see how it *guarantees* no collision with other devices of the
> same class...

I checked and there is no other NVIDIA cards with UNKNOWN class code. 
Moreover, even if the driver gets loaded for a wrong card then eventually
i2c_read() (initiated from UCSI driver) will timeout or UCSI commands will
timeout. I think this is safe enough for now. We will update the class code
when UCSI gets a PCI class code.

We don't want to add dependency of adding product id for any new card
which requires this driver.
 
> > +#define PCI_CLASS_SERIAL_UNKNOWN   0x0c80
> > +static const struct pci_device_id gpu_i2c_ids[] = {
> 
> > +   { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
> > +   PCI_CLASS_SERIAL_UNKNOWN << 8, 0xff00},
> 
> ...for now, I would suggest to be more stricted, i.e.
> 
> { PCI_VDEVICE(NVIDIA, 0x1ad9) },
> 
> Whenever the class appears it can be added later on.
See above.
> 
> > +   { }
> > +};
> > +MODULE_DEVICE_TABLE(pci,

RE: [PATCH v4 1/2] i2c: buses: add i2c bus driver for NVIDIA GPU

2018-08-31 Thread Ajay Gupta
Hi Andy

> > > Latest NVIDIA GPU card has USB Type-C interface. There is a Type-C
> > > controller which can be accessed over I2C.
> > > +   val &= ~(I2C_MST_CNTL_GEN_START | I2C_MST_CNTL_GEN_STOP
> > > +   | I2C_MST_CNTL_GEN_RAB);
> >
> > "|" should be on previous line to follow common style in this module.
> The "|" here is to clear the bit together.  [val &= ~(X | Y | Z)] Style in 
> this
> module is still followed. Please see first line which does "|" to val.
Ok, I got your point of putting "|" on line above and will fix it.

Thanks
Ajay

--
nvpublic
--
> 
> > > +   writel(val, i2cd->regs + I2C_MST_CNTL);
> > > +
> > > +   return i2c_check_status(i2cd); }
> > > +
> > > +static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
> > > +  struct i2c_msg *msgs, int num) {
> > > +   struct gpu_i2c_dev *i2cd = i2c_get_adapdata(adap);
> > > +   struct device *dev = i2cd->dev;
> > > +   int status;
> > > +   int i, j;
> >


[PATCH v5 1/2] i2c: buses: add i2c bus driver for NVIDIA GPU

2018-08-31 Thread Ajay Gupta
Latest NVIDIA GPU card has USB Type-C interface. There is a
Type-C controller which can be accessed over I2C.

This driver adds I2C bus driver to communicate with Type-C controller.
I2C client driver will be part of USB Type-C UCSI driver.

Signed-off-by: Ajay Gupta 
---
Changes from v1 -> v2
None
Changes from v2 -> v3
Fixed review comments from Andy and Thierry
Rename i2c-gpu.c -> i2c-nvidia-gpu.c
Changes from v3 -> v4
Fixed review comments from Andy
Changes from v4 -> v5
Fixed review comments from Andy

 Documentation/i2c/busses/i2c-nvidia-gpu |  18 ++
 MAINTAINERS |   7 +
 drivers/i2c/busses/Kconfig  |   9 +
 drivers/i2c/busses/Makefile |   1 +
 drivers/i2c/busses/i2c-nvidia-gpu.c | 405 
 5 files changed, 440 insertions(+)
 create mode 100644 Documentation/i2c/busses/i2c-nvidia-gpu
 create mode 100644 drivers/i2c/busses/i2c-nvidia-gpu.c

diff --git a/Documentation/i2c/busses/i2c-nvidia-gpu 
b/Documentation/i2c/busses/i2c-nvidia-gpu
new file mode 100644
index 000..31884d2
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-nvidia-gpu
@@ -0,0 +1,18 @@
+Kernel driver i2c-nvidia-gpu
+
+Datasheet: not publicly available.
+
+Authors:
+   Ajay Gupta 
+
+Description
+---
+
+i2c-nvidia-gpu is a driver for I2C controller included in NVIDIA Turing
+and later GPUs and it is used to communicate with Type-C controller on GPUs.
+
+If your 'lspci -v' listing shows something like the following,
+
+01:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device 1ad9 (rev a1)
+
+then this driver should support the I2C controller of your GPU.
diff --git a/MAINTAINERS b/MAINTAINERS
index 9ad052a..2d1c5a1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6797,6 +6797,13 @@ L:   linux-a...@vger.kernel.org
 S: Maintained
 F: drivers/i2c/i2c-core-acpi.c
 
+I2C CONTROLLER DRIVER FOR NVIDIA GPU
+M: Ajay Gupta 
+L: linux-...@vger.kernel.org
+S: Maintained
+F: Documentation/i2c/busses/i2c-nvidia-gpu
+F: drivers/i2c/busses/i2c-nvidia-gpu.c
+
 I2C MUXES
 M: Peter Rosin 
 L: linux-...@vger.kernel.org
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 451d4ae..eed827b 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -224,6 +224,15 @@ config I2C_NFORCE2_S4985
  This driver can also be built as a module.  If so, the module
  will be called i2c-nforce2-s4985.
 
+config I2C_NVIDIA_GPU
+   tristate "NVIDIA GPU I2C controller"
+   depends on PCI
+   help
+ If you say yes to this option, support will be included for the
+ NVIDIA GPU I2C controller which is used to communicate with the GPU's
+ Type-C controller. This driver can also be built as a module called
+ i2c-nvidia-gpu.
+
 config I2C_SIS5595
tristate "SiS 5595"
depends on PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 18b26af..d499813 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -140,5 +140,6 @@ obj-$(CONFIG_I2C_SIBYTE)+= i2c-sibyte.o
 obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o
 obj-$(CONFIG_SCx200_ACB)   += scx200_acb.o
 obj-$(CONFIG_I2C_FSI)  += i2c-fsi.o
+obj-$(CONFIG_I2C_NVIDIA_GPU)   += i2c-nvidia-gpu.o
 
 ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
new file mode 100644
index 000..2ce6706
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -0,0 +1,405 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nvidia GPU I2C controller Driver
+ *
+ * Copyright (C) 2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta 
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+/* I2C definitions */
+#define I2C_MST_CNTL   0x00
+#define I2C_MST_CNTL_GEN_START BIT(0)
+#define I2C_MST_CNTL_GEN_STOP  BIT(1)
+#define I2C_MST_CNTL_CMD_NONE  (0 << 2)
+#define I2C_MST_CNTL_CMD_READ  (1 << 2)
+#define I2C_MST_CNTL_CMD_WRITE (2 << 2)
+#define I2C_MST_CNTL_GEN_RAB   BIT(4)
+#define I2C_MST_CNTL_BURST_SIZE_SHIFT  6
+#define I2C_MST_CNTL_GEN_NACK  BIT(28)
+#define I2C_MST_CNTL_STATUSGENMASK(30, 29)
+#define I2C_MST_CNTL_STATUS_OKAY   (0 << 29)
+#define I2C_MST_CNTL_STATUS_NO_ACK (1 << 29)
+#define I2C_MST_CNTL_STATUS_TIMEOUT(2 << 29)
+#define I2C_MST_CNTL_STATUS_BUS_BUSY   (3 << 29)
+#define I2C_MST_CNTL_CYCLE_TRIGGER BIT(31)
+
+#define I2C_MST_ADDR   0x04
+#define I2C_MST_ADDR_DAB   0
+
+#define I2C_MS

[PATCH v5 2/2] usb: typec: ucsi: add support for Cypress CCGx

2018-08-31 Thread Ajay Gupta
Latest NVIDIA GPU cards have a Cypress CCGx Type-C controller
over I2C interface.

This UCSI I2C driver uses I2C bus driver interface for communicating
with Type-C controller.

Signed-off-by: Ajay Gupta 
---
Changes from v1 -> v2
Fixed identation in drivers/usb/typec/ucsi/Kconfig
Changes from v2 -> v3
Fixed most of comments from Heikki
Rename ucsi_i2c_ccg.c -> ucsi_ccg.c
Changes from v3 -> v4
Fixed comments from Andy
Changes from v4 -> v5
Fixed comments from Andy

 drivers/usb/typec/ucsi/Kconfig|  10 +
 drivers/usb/typec/ucsi/Makefile   |   2 +
 drivers/usb/typec/ucsi/ucsi_ccg.c | 390 ++
 3 files changed, 402 insertions(+)
 create mode 100644 drivers/usb/typec/ucsi/ucsi_ccg.c

diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig
index e36d6c7..7811888 100644
--- a/drivers/usb/typec/ucsi/Kconfig
+++ b/drivers/usb/typec/ucsi/Kconfig
@@ -23,6 +23,16 @@ config TYPEC_UCSI
 
 if TYPEC_UCSI
 
+config UCSI_CCG
+   tristate "UCSI Interface Driver for Cypress CCGx"
+   depends on I2C
+   help
+ This driver enables UCSI support on platforms that expose a
+ Cypress CCGx Type-C controller over I2C interface.
+
+ To compile the driver as a module, choose M here: the module will be
+ called ucsi_ccg.
+
 config UCSI_ACPI
tristate "UCSI ACPI Interface Driver"
depends on ACPI
diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile
index 7afbea5..2f4900b 100644
--- a/drivers/usb/typec/ucsi/Makefile
+++ b/drivers/usb/typec/ucsi/Makefile
@@ -8,3 +8,5 @@ typec_ucsi-y:= ucsi.o
 typec_ucsi-$(CONFIG_TRACING)   += trace.o
 
 obj-$(CONFIG_UCSI_ACPI)+= ucsi_acpi.o
+
+obj-$(CONFIG_UCSI_CCG) += ucsi_ccg.o
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
new file mode 100644
index 000..1e7c3b2
--- /dev/null
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -0,0 +1,390 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * UCSI driver for Cypress CCGx Type-C controller
+ *
+ * Copyright (C) 2017-2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta 
+ *
+ * Some code borrowed from drivers/usb/typec/ucsi/ucsi_acpi.c
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include "ucsi.h"
+
+struct ucsi_ccg {
+   struct device *dev;
+   struct ucsi *ucsi;
+   struct ucsi_ppm ppm;
+   struct i2c_client *client;
+   int irq;
+};
+
+#define CCGX_I2C_RAB_DEVICE_MODE   0x00
+#define CCGX_I2C_RAB_READ_SILICON_ID   0x2
+#define CCGX_I2C_RAB_INTR_REG  0x06
+#define CCGX_I2C_RAB_FW1_VERSION   0x28
+#define CCGX_I2C_RAB_FW2_VERSION   0x20
+#define CCGX_I2C_RAB_UCSI_CONTROL  0x39
+#define CCGX_I2C_RAB_UCSI_CONTROL_STARTBIT(0)
+#define CCGX_I2C_RAB_UCSI_CONTROL_STOP BIT(1)
+#define CCGX_I2C_RAB_RESPONSE_REG  0x7E
+#define CCGX_I2C_RAB_UCSI_DATA_BLOCK   0xf000
+
+static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
+{
+   struct device *dev = uc->dev;
+   struct i2c_client *client = uc->client;
+   unsigned char buf[2];
+   struct i2c_msg msgs[] = {
+   {
+   .addr   = client->addr,
+   .flags  = 0x0,
+   .len= 0x2,
+   .buf= buf,
+   },
+   {
+   .addr   = client->addr,
+   .flags  = I2C_M_RD,
+   .buf= data,
+   },
+   };
+   u32 rlen, rem_len = len;
+   int err;
+
+   while (rem_len > 0) {
+   msgs[1].buf = &data[len - rem_len];
+   rlen = min_t(u16, rem_len, 4);
+   msgs[1].len = rlen;
+   put_unaligned_le16(rab, buf);
+   err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+   if (err < 0) {
+   dev_err(dev, "i2c_transfer failed, err %d\n", err);
+   return err;
+   }
+   rab += rlen;
+   rem_len -= rlen;
+   }
+
+   return 0;
+}
+
+static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
+{
+   struct device *dev = uc->dev;
+   struct i2c_client *client = uc->client;
+   unsigned char buf[2];
+   struct i2c_msg msgs[] = {
+   {
+   .addr   = client->addr,
+   .flags  = 0x0,
+   .len= 0x2,
+   .buf= buf,
+   },
+   {
+   .addr   = client->addr,
+   

RE: [PATCH v4 2/2] usb: typec: ucsi: add support for Cypress CCGx

2018-08-31 Thread Ajay Gupta
Hi Andy,
> > Latest NVIDIA GPU cards have a Cypress CCGx Type-C controller over I2C
> > interface.
> >
> > This UCSI I2C driver uses I2C bus driver interface for communicating
> > with Type-C controller.
> 
> > Changes from v3 -> v4
> > Fixed comments from Andy
> 
> Unfortunatelly not all comments was addressed, see below.
> 
> > +   if (err == ARRAY_SIZE(msgs)) {
> > +   err = 0;
> > +   } else if (err >= 0) {
> > +   dev_err(dev, "i2c_transfer failed, err %d\n", err);
> > +   return -EIO;
> > +   }
> 
> Shouldn't be simple
> if (err < 0) {
>  ...
>  return err;
> }
> 
> ?
Ok, will fix
> 
> > +   if (err == ARRAY_SIZE(msgs)) {
> > +   err = 0;
> > +   } else if (err >= 0) {
> > +   dev_err(dev, "i2c_transfer failed, err %d\n", err);
> > +   return -EIO;
> > +   }
> 
> Ditto.
ok
> 
> > +   struct device *dev = uc->dev;
> > +   u8 data[64];
> > +   int err;
> 
> > +   unsigned int count = 10;
> 
> Move this line upper a bit.
ok
> 
> > +   unsigned char buf[3] = {
> > +   CCGX_I2C_RAB_INTR_REG & 0xff, CCGX_I2C_RAB_INTR_REG >>
> > + 8, 0x0};
> 
> This should follow the style you applied earlier in the same file.
> 
> Also, & 0xff is redundant (better just to use >> 0).
Ok, even ">> 0" will be redundant so will just drop  "& 0xff".

> > +   struct ucsi_ccg *uc = container_of(ppm,
> > +   struct ucsi_ccg, ppm);
> 
> One line?
ok
> 
> > +static int ucsi_ccg_cmd(struct ucsi_ppm *ppm, struct ucsi_control
> > +*ctrl) {
> > +   struct ucsi_ccg *uc = container_of(ppm, struct ucsi_ccg, ppm);
> 
> > +   int err = 0;
> 
> Redundant assignment.
ok
> 
> > +
> > +   ppm->data->ctrl.raw_cmd = ctrl->raw_cmd;
> > +   err = ucsi_ccg_send_data(uc);
> > +
> > +   return err;
> > +}
> 
> > +static int ucsi_ccg_probe(struct i2c_client *client,
> > + const struct i2c_device_id *id)
> 
> One line?
It crosses column width of 80. It takes total 85.

> 
> > +static const struct i2c_device_id ucsi_ccg_device_id[] = {
> > +   {"ccgx-ucsi", 0},
> 
> > +   {},
> 
> Terminator better w/o comma.
Ok.
> 
> > +};
> > +MODULE_DEVICE_TABLE(i2c, ucsi_ccg_device_id);
> 
Thanks
Ajay

--
nvpublic
--
> --
> With Best Regards,
> Andy Shevchenko


RE: [PATCH v5 2/2] usb: typec: ucsi: add support for Cypress CCGx

2018-09-05 Thread Ajay Gupta
Hi Greg,
> On Fri, Aug 31, 2018 at 01:22:21PM -0700, Ajay Gupta wrote:
> > +   dev_info(dev, "Silicon id %2ph", data +
> CCGX_I2C_RAB_READ_SILICON_ID);
> > +   dev_info(dev, "FW1 version %8ph\n", data +
> CCGX_I2C_RAB_FW1_VERSION);
> > +   dev_info(dev, "FW2 version %8ph\n", data +
> > +CCGX_I2C_RAB_FW2_VERSION);
> 
> Drivers should be totally quiet when initialized, unless something goes wrong.
> Please don't spam the kernel log with this type of stuff.
> 
> You can use dev_dbg() if it helps with debugging the code, that might be a
> better idea here.
Ok, will use dev_dbg().
 
> Also, a pointer?  Are you sure about that?  That looks really odd...
Yes, FW version is 8 byte hex code at address 
data + CCGX_I2C_RAB_FWx_VERSION

Thanks
Ajay

--
nvpublic
-- 


RE: [PATCH v5 2/2] usb: typec: ucsi: add support for Cypress CCGx

2018-09-05 Thread Ajay Gupta
Hi Greg,

> > +static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
> > +{
> > +   struct device *dev = uc->dev;
> > +   struct i2c_client *client = uc->client;
> > +   unsigned char buf[2];
> > +   struct i2c_msg msgs[] = {
> > +   {
> > +   .addr   = client->addr,
> > +   .flags  = 0x0,
> > +   .len= 0x2,
> > +   .buf= buf,
> > +   },
> > +   {
> > +   .addr   = client->addr,
> > +   .flags  = I2C_M_RD,
> > +   .buf= data,
> > +   },
> > +   };
> 
> Are you sure you are allowed to do i2c messages off of the stack like this?
> Will that work on all platforms?
Most of the drivers in kernel today seem to use stack memory for
i2c_transfer() but I will fix it in next version.
 
> > +   u32 rlen, rem_len = len;
> > +   int err;
> > +
> > +   while (rem_len > 0) {
> > +   msgs[1].buf = &data[len - rem_len];
> > +   rlen = min_t(u16, rem_len, 4);
> > +   msgs[1].len = rlen;
> > +   put_unaligned_le16(rab, buf);
> > +   err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
> > +   if (err < 0) {
> > +   dev_err(dev, "i2c_transfer failed, err %d\n", err);
> 
> You are printing out an error here, no need to print out another error every
> time you call this function and it fails, right?  Only do it in one place, 
> otherwise
> it is extra noisy when things fail.
I will fix and add error print in only one location. I think better to keep it 
here
only and remove error print line from all the caller of this function.
 
> > +   return err;
> > +   }
> > +   rab += rlen;
> > +   rem_len -= rlen;
> > +   }
> > +
> > +   return 0;
> > +}
> > +
> > +static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
> > +{
> > +   struct device *dev = uc->dev;
> > +   struct i2c_client *client = uc->client;
> > +   unsigned char buf[2];
> > +   struct i2c_msg msgs[] = {
> > +   {
> > +   .addr   = client->addr,
> > +   .flags  = 0x0,
> > +   .len= 0x2,
> > +   .buf= buf,
> > +   },
> > +   {
> > +   .addr   = client->addr,
> > +   .flags  = 0x0,
> > +   .buf= data,
> > +   .len= len,
> > +   },
> > +   {
> > +   .addr   = client->addr,
> > +   .flags  = I2C_M_STOP,
> > +   },
> > +   };
> > +   int err;
> 
> Same question here, i2c message off of the stack?
> 
> > +
> > +   put_unaligned_le16(rab, buf);
> > +   err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
> > +   if (err < 0) {
> > +   dev_err(dev, "i2c_transfer failed, err %d\n", err);
> > +   return err;
> 
> And again, only print an error in one place please.
Ok.
 
> This can be simplified to just:
>   return i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); right?
Only issue is that i2c_transfer() return number of messages on success but ucsi
APIs sync() and cmd() at drivers/usb/typec/ucsi/ucsi.h expects return 
value of '0' on success.

> > +   }
> > +
> > +   return 0;
> > +}
> > +
> > +static int ucsi_ccg_init(struct ucsi_ccg *uc) {
> > +   struct device *dev = uc->dev;
> > +   unsigned int count = 10;
> > +   u8 data[64];
> > +   int err;
> > +
> > +   /*
> > +* Selectively issue device reset
> > +* - if RESPONSE register is RESET_COMPLETE, do not issue device
> reset
> > +*   (will cause usb device disconnect / reconnect)
> > +* - if RESPONSE register is not RESET_COMPLETE, issue device reset
> > +*   (causes PPC to resync device connect state by re-issuing
> > +*   set mux command)
> > +*/
> > +   data[0] = 0x00;
> > +   data[1] = 0x00;
> 
> Again, it's ok to do messages off of the stack?
Will fix.

Thanks
Ajay

--
nvpublic
--
> 
> thanks,
> 
> greg k-h


[PATCH v6 1/2] i2c: buses: add i2c bus driver for NVIDIA GPU

2018-09-05 Thread Ajay Gupta
Latest NVIDIA GPU card has USB Type-C interface. There is a
Type-C controller which can be accessed over I2C.

This driver adds I2C bus driver to communicate with Type-C controller.
I2C client driver will be part of USB Type-C UCSI driver.

Signed-off-by: Ajay Gupta 
---
Changes from v1 -> v2
None
Changes from v2 -> v3
Fixed review comments from Andy and Thierry
Rename i2c-gpu.c -> i2c-nvidia-gpu.c
Changes from v3 -> v4
Fixed review comments from Andy
Changes from v4 -> v5
Fixed review comments from Andy
Changes from v5 -> v6
None 

 Documentation/i2c/busses/i2c-nvidia-gpu |  18 ++
 MAINTAINERS |   7 +
 drivers/i2c/busses/Kconfig  |   9 +
 drivers/i2c/busses/Makefile |   1 +
 drivers/i2c/busses/i2c-nvidia-gpu.c | 405 
 5 files changed, 440 insertions(+)
 create mode 100644 Documentation/i2c/busses/i2c-nvidia-gpu
 create mode 100644 drivers/i2c/busses/i2c-nvidia-gpu.c

diff --git a/Documentation/i2c/busses/i2c-nvidia-gpu 
b/Documentation/i2c/busses/i2c-nvidia-gpu
new file mode 100644
index 000..31884d2
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-nvidia-gpu
@@ -0,0 +1,18 @@
+Kernel driver i2c-nvidia-gpu
+
+Datasheet: not publicly available.
+
+Authors:
+   Ajay Gupta 
+
+Description
+---
+
+i2c-nvidia-gpu is a driver for I2C controller included in NVIDIA Turing
+and later GPUs and it is used to communicate with Type-C controller on GPUs.
+
+If your 'lspci -v' listing shows something like the following,
+
+01:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device 1ad9 (rev a1)
+
+then this driver should support the I2C controller of your GPU.
diff --git a/MAINTAINERS b/MAINTAINERS
index 9ad052a..2d1c5a1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6797,6 +6797,13 @@ L:   linux-a...@vger.kernel.org
 S: Maintained
 F: drivers/i2c/i2c-core-acpi.c
 
+I2C CONTROLLER DRIVER FOR NVIDIA GPU
+M: Ajay Gupta 
+L: linux-...@vger.kernel.org
+S: Maintained
+F: Documentation/i2c/busses/i2c-nvidia-gpu
+F: drivers/i2c/busses/i2c-nvidia-gpu.c
+
 I2C MUXES
 M: Peter Rosin 
 L: linux-...@vger.kernel.org
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 451d4ae..eed827b 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -224,6 +224,15 @@ config I2C_NFORCE2_S4985
  This driver can also be built as a module.  If so, the module
  will be called i2c-nforce2-s4985.
 
+config I2C_NVIDIA_GPU
+   tristate "NVIDIA GPU I2C controller"
+   depends on PCI
+   help
+ If you say yes to this option, support will be included for the
+ NVIDIA GPU I2C controller which is used to communicate with the GPU's
+ Type-C controller. This driver can also be built as a module called
+ i2c-nvidia-gpu.
+
 config I2C_SIS5595
tristate "SiS 5595"
depends on PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 18b26af..d499813 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -140,5 +140,6 @@ obj-$(CONFIG_I2C_SIBYTE)+= i2c-sibyte.o
 obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o
 obj-$(CONFIG_SCx200_ACB)   += scx200_acb.o
 obj-$(CONFIG_I2C_FSI)  += i2c-fsi.o
+obj-$(CONFIG_I2C_NVIDIA_GPU)   += i2c-nvidia-gpu.o
 
 ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
new file mode 100644
index 000..2ce6706
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -0,0 +1,405 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nvidia GPU I2C controller Driver
+ *
+ * Copyright (C) 2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta 
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+/* I2C definitions */
+#define I2C_MST_CNTL   0x00
+#define I2C_MST_CNTL_GEN_START BIT(0)
+#define I2C_MST_CNTL_GEN_STOP  BIT(1)
+#define I2C_MST_CNTL_CMD_NONE  (0 << 2)
+#define I2C_MST_CNTL_CMD_READ  (1 << 2)
+#define I2C_MST_CNTL_CMD_WRITE (2 << 2)
+#define I2C_MST_CNTL_GEN_RAB   BIT(4)
+#define I2C_MST_CNTL_BURST_SIZE_SHIFT  6
+#define I2C_MST_CNTL_GEN_NACK  BIT(28)
+#define I2C_MST_CNTL_STATUSGENMASK(30, 29)
+#define I2C_MST_CNTL_STATUS_OKAY   (0 << 29)
+#define I2C_MST_CNTL_STATUS_NO_ACK (1 << 29)
+#define I2C_MST_CNTL_STATUS_TIMEOUT(2 << 29)
+#define I2C_MST_CNTL_STATUS_BUS_BUSY   (3 << 29)
+#define I2C_MST_CNTL_CYCLE_TRIGGER BIT(31)
+
+#define I2C_MST_ADDR   0x04
+#define I2C_MST_ADDR_DAB 

[PATCH v6 2/2] usb: typec: ucsi: add support for Cypress CCGx

2018-09-05 Thread Ajay Gupta
Latest NVIDIA GPU cards have a Cypress CCGx Type-C controller
over I2C interface.

This UCSI I2C driver uses I2C bus driver interface for communicating
with Type-C controller.

Signed-off-by: Ajay Gupta 
---
Changes from v1 -> v2
Fixed identation in drivers/usb/typec/ucsi/Kconfig
Changes from v2 -> v3
Fixed most of comments from Heikki
Rename ucsi_i2c_ccg.c -> ucsi_ccg.c
Changes from v3 -> v4
Fixed comments from Andy
Changes from v4 -> v5
Fixed comments from Andy
Changes from v5 -> v6
Fixed review comments from Greg 

 drivers/usb/typec/ucsi/Kconfig|  10 +
 drivers/usb/typec/ucsi/Makefile   |   2 +
 drivers/usb/typec/ucsi/ucsi_ccg.c | 382 ++
 3 files changed, 394 insertions(+)
 create mode 100644 drivers/usb/typec/ucsi/ucsi_ccg.c

diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig
index e36d6c7..7811888 100644
--- a/drivers/usb/typec/ucsi/Kconfig
+++ b/drivers/usb/typec/ucsi/Kconfig
@@ -23,6 +23,16 @@ config TYPEC_UCSI
 
 if TYPEC_UCSI
 
+config UCSI_CCG
+   tristate "UCSI Interface Driver for Cypress CCGx"
+   depends on I2C
+   help
+ This driver enables UCSI support on platforms that expose a
+ Cypress CCGx Type-C controller over I2C interface.
+
+ To compile the driver as a module, choose M here: the module will be
+ called ucsi_ccg.
+
 config UCSI_ACPI
tristate "UCSI ACPI Interface Driver"
depends on ACPI
diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile
index 7afbea5..2f4900b 100644
--- a/drivers/usb/typec/ucsi/Makefile
+++ b/drivers/usb/typec/ucsi/Makefile
@@ -8,3 +8,5 @@ typec_ucsi-y:= ucsi.o
 typec_ucsi-$(CONFIG_TRACING)   += trace.o
 
 obj-$(CONFIG_UCSI_ACPI)+= ucsi_acpi.o
+
+obj-$(CONFIG_UCSI_CCG) += ucsi_ccg.o
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
new file mode 100644
index 000..65292bf
--- /dev/null
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -0,0 +1,382 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * UCSI driver for Cypress CCGx Type-C controller
+ *
+ * Copyright (C) 2017-2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta 
+ *
+ * Some code borrowed from drivers/usb/typec/ucsi/ucsi_acpi.c
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include "ucsi.h"
+
+struct ucsi_ccg {
+   struct device *dev;
+   struct ucsi *ucsi;
+   struct ucsi_ppm ppm;
+   struct i2c_client *client;
+   int irq;
+};
+
+#define CCGX_I2C_RAB_DEVICE_MODE   0x00
+#define CCGX_I2C_RAB_READ_SILICON_ID   0x2
+#define CCGX_I2C_RAB_INTR_REG  0x06
+#define CCGX_I2C_RAB_FW1_VERSION   0x28
+#define CCGX_I2C_RAB_FW2_VERSION   0x20
+#define CCGX_I2C_RAB_UCSI_CONTROL  0x39
+#define CCGX_I2C_RAB_UCSI_CONTROL_STARTBIT(0)
+#define CCGX_I2C_RAB_UCSI_CONTROL_STOP BIT(1)
+#define CCGX_I2C_RAB_RESPONSE_REG  0x7E
+#define CCGX_I2C_RAB_UCSI_DATA_BLOCK   0xf000
+
+static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
+{
+   struct i2c_client *client = uc->client;
+   unsigned char *buf;
+   struct i2c_msg *msgs;
+   u32 rlen, rem_len = len;
+   int status;
+
+   buf = kzalloc(2, GFP_KERNEL);
+   if (!buf)
+   return -ENOMEM;
+
+   msgs = kcalloc(2, sizeof(struct i2c_msg), GFP_KERNEL);
+   if (!msgs) {
+   kfree(buf);
+   return -ENOMEM;
+   }
+
+   msgs[0].addr = client->addr;
+   msgs[0].len = 2;
+   msgs[0].buf = buf;
+   msgs[1].addr = client->addr;
+   msgs[1].flags = I2C_M_RD;
+
+   while (rem_len > 0) {
+   msgs[1].buf = &data[len - rem_len];
+   rlen = min_t(u16, rem_len, 4);
+   msgs[1].len = rlen;
+   put_unaligned_le16(rab, buf);
+   status = i2c_transfer(client->adapter, msgs, 2);
+   if (status < 0) {
+   dev_err(uc->dev, "i2c_transfer failed %d", status);
+   kfree(buf);
+   kfree(msgs);
+   return status;
+   }
+   rab += rlen;
+   rem_len -= rlen;
+   }
+
+   kfree(buf);
+   kfree(msgs);
+   return 0;
+}
+
+static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
+{
+   struct i2c_client *client = uc->client;
+   unsigned char *buf;
+   struct i2c_msg *msgs;
+   int status;
+
+   buf = kzalloc(2, GFP_KERNEL);
+   if (!buf)
+   return -ENOMEM;
+
+   msgs = kcalloc(3, sizeof(struct i2c_msg), GFP_KE

RE: [PATCH v6 1/2] i2c: buses: add i2c bus driver for NVIDIA GPU

2018-09-06 Thread Ajay Gupta
Hi Peter,

> > Latest NVIDIA GPU card has USB Type-C interface. There is a Type-C
> > controller which can be accessed over I2C.
> >
> > This driver adds I2C bus driver to communicate with Type-C controller.
> > I2C client driver will be part of USB Type-C UCSI driver.
> >
> > Signed-off-by: Ajay Gupta 

> > +static void enable_i2c_bus(struct gpu_i2c_dev *i2cd)
> 
> Please prefix all your functions with gpu_, or nvidia_gpu_ or something like
> that (because gpu sounds like a something graphics, not that nvidia_gpu helps
> with that problem though...)
Ok, will prefix them.
 
> > +{
> > +   u32 val;
> > +
> > +   /* enable I2C */
> > +   val = readl(i2cd->regs + I2C_MST_HYBRID_PADCTL);
> > +   val |= I2C_MST_HYBRID_PADCTL_MODE_I2C |
> > +   I2C_MST_HYBRID_PADCTL_I2C_SCL_INPUT_RCV |
> > +   I2C_MST_HYBRID_PADCTL_I2C_SDA_INPUT_RCV;
> > +   writel(val, i2cd->regs + I2C_MST_HYBRID_PADCTL);
> > +
> > +   /* enable 100KHZ mode */
> > +   val = I2C_MST_I2C0_TIMING_SCL_PERIOD_100KHZ;
> > +   val |= (I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT_MAX
> > +   << I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT);
> > +   val |= I2C_MST_I2C0_TIMING_TIMEOUT_CHECK;
> > +   writel(val, i2cd->regs + I2C_MST_I2C0_TIMING); }
> > +
> > +static int i2c_check_status(struct gpu_i2c_dev *i2cd) {
> > +   unsigned long target = jiffies + msecs_to_jiffies(1000);
> > +   u32 val;
> > +
> > +   do {
> > +   val = readl(i2cd->regs + I2C_MST_CNTL);
> > +   if (!(val & I2C_MST_CNTL_CYCLE_TRIGGER))
> > +   break;
> > +   if ((val & I2C_MST_CNTL_STATUS) !=
> > +   I2C_MST_CNTL_STATUS_BUS_BUSY)
> > +   break;
> > +   usleep_range(1000, 2000);
> > +   } while (time_is_after_jiffies(target));
> > +   if (time_is_before_jiffies(target))
> > +   return -EIO;
> > +
> > +   val = readl(i2cd->regs + I2C_MST_CNTL);
> > +   switch (val & I2C_MST_CNTL_STATUS) {
> > +   case I2C_MST_CNTL_STATUS_OKAY:
> > +   return 0;
> > +   case I2C_MST_CNTL_STATUS_NO_ACK:
> > +   return -EIO;
> > +   case I2C_MST_CNTL_STATUS_TIMEOUT:
> > +   return -ETIME;
> > +   case I2C_MST_CNTL_STATUS_BUS_BUSY:
> > +   return -EBUSY;
> > +   default:
> > +   return 0;
> > +   }
> > +}
> > +
> > +static int i2c_read(struct gpu_i2c_dev *i2cd, u8 *data, u16 len) {
> > +   int status;
> > +   u32 val;
> > +
> > +   val = I2C_MST_CNTL_GEN_START | I2C_MST_CNTL_GEN_STOP |
> > +   I2C_MST_CNTL_CMD_READ | (len <<
> I2C_MST_CNTL_BURST_SIZE_SHIFT) |
> > +   I2C_MST_CNTL_CYCLE_TRIGGER |
> I2C_MST_CNTL_GEN_NACK;
> > +   val &= ~I2C_MST_CNTL_GEN_RAB;
> > +   writel(val, i2cd->regs + I2C_MST_CNTL);
> > +
> > +   status = i2c_check_status(i2cd);
> > +   if (status < 0)
> > +   return status;
> > +
> > +   val = readl(i2cd->regs + I2C_MST_DATA);
> > +   switch (len) {
> > +   case 1:
> > +   data[0] = val;
> > +   break;
> > +   case 2:
> > +   put_unaligned_be16(val, data);
> > +   break;
> > +   case 3:
> > +   put_unaligned_be16(val >> 8, data);
> > +   data[2] = val;
> > +   break;
> > +   case 4:
> > +   put_unaligned_be32(val, data);
> > +   break;
> > +   default:
> 
> This seems to behave rather strange for len > 4, and I do not see anything
> preventing that from happening.
Actually the check is in ccg_read() of the 
client driver at https://marc.info/?l=linux-usb&m=153618608301206&w=2 

> Am I missing something, or do you need to add a quirk for max_read_len?
I will add a check in this function as well.

> > +   break;
> > +   }
> > +   return status;
> > +}
> > +
> > +static int i2c_start(struct gpu_i2c_dev *i2cd, u16 addr) {
> > +   u32 val;
> > +
> > +   val = addr << I2C_MST_ADDR_DAB;
> > +   writel(val, i2cd->regs + I2C_MST_ADDR);
> > +
> > +   val = I2C_MST_CNTL_GEN_START | I2C_MST_CNTL_CMD_NONE |
> > +   I2C_MST_CNTL_GEN_NACK;
> > +   val &= ~(I2C_MST_CNTL_GEN_STOP | I2C_MST_CNTL_GEN_RAB);
> > +   writel(val, i2cd->regs + I2C_MST_CNTL);
> > +
> > +   return i2c_check_status(i2cd);
> > +}
> > +
> > +static int i2c_stop(struct gpu_i2c_dev *i2cd) {
> > +   u32 val;
> > +
> > +   va

[PATCH v7 1/2] i2c: buses: add i2c bus driver for NVIDIA GPU

2018-09-06 Thread Ajay Gupta
Latest NVIDIA GPU card has USB Type-C interface. There is a
Type-C controller which can be accessed over I2C.

This driver adds I2C bus driver to communicate with Type-C controller.
I2C client driver will be part of USB Type-C UCSI driver.

Signed-off-by: Ajay Gupta 
Reviewed-by: Andy Shevchenko 
Reviewed-by: Heikki Krogerus 
---
Changes from v1 -> v2
None
Changes from v2 -> v3
Fixed review comments from Andy and Thierry
Rename i2c-gpu.c -> i2c-nvidia-gpu.c
Changes from v3 -> v4
Fixed review comments from Andy
Changes from v4 -> v5
Fixed review comments from Andy
Changes from v5 -> v6
None 
Changes from v6 -> v7
Fixed review comments from Peter 

 Documentation/i2c/busses/i2c-nvidia-gpu |  18 ++
 MAINTAINERS |   7 +
 drivers/i2c/busses/Kconfig  |   9 +
 drivers/i2c/busses/Makefile |   1 +
 drivers/i2c/busses/i2c-nvidia-gpu.c | 394 
 5 files changed, 429 insertions(+)
 create mode 100644 Documentation/i2c/busses/i2c-nvidia-gpu
 create mode 100644 drivers/i2c/busses/i2c-nvidia-gpu.c

diff --git a/Documentation/i2c/busses/i2c-nvidia-gpu 
b/Documentation/i2c/busses/i2c-nvidia-gpu
new file mode 100644
index 000..31884d2
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-nvidia-gpu
@@ -0,0 +1,18 @@
+Kernel driver i2c-nvidia-gpu
+
+Datasheet: not publicly available.
+
+Authors:
+   Ajay Gupta 
+
+Description
+---
+
+i2c-nvidia-gpu is a driver for I2C controller included in NVIDIA Turing
+and later GPUs and it is used to communicate with Type-C controller on GPUs.
+
+If your 'lspci -v' listing shows something like the following,
+
+01:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device 1ad9 (rev a1)
+
+then this driver should support the I2C controller of your GPU.
diff --git a/MAINTAINERS b/MAINTAINERS
index 9ad052a..2d1c5a1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6797,6 +6797,13 @@ L:   linux-a...@vger.kernel.org
 S: Maintained
 F: drivers/i2c/i2c-core-acpi.c
 
+I2C CONTROLLER DRIVER FOR NVIDIA GPU
+M: Ajay Gupta 
+L: linux-...@vger.kernel.org
+S: Maintained
+F: Documentation/i2c/busses/i2c-nvidia-gpu
+F: drivers/i2c/busses/i2c-nvidia-gpu.c
+
 I2C MUXES
 M: Peter Rosin 
 L: linux-...@vger.kernel.org
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 451d4ae..eed827b 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -224,6 +224,15 @@ config I2C_NFORCE2_S4985
  This driver can also be built as a module.  If so, the module
  will be called i2c-nforce2-s4985.
 
+config I2C_NVIDIA_GPU
+   tristate "NVIDIA GPU I2C controller"
+   depends on PCI
+   help
+ If you say yes to this option, support will be included for the
+ NVIDIA GPU I2C controller which is used to communicate with the GPU's
+ Type-C controller. This driver can also be built as a module called
+ i2c-nvidia-gpu.
+
 config I2C_SIS5595
tristate "SiS 5595"
depends on PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 18b26af..d499813 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -140,5 +140,6 @@ obj-$(CONFIG_I2C_SIBYTE)+= i2c-sibyte.o
 obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o
 obj-$(CONFIG_SCx200_ACB)   += scx200_acb.o
 obj-$(CONFIG_I2C_FSI)  += i2c-fsi.o
+obj-$(CONFIG_I2C_NVIDIA_GPU)   += i2c-nvidia-gpu.o
 
 ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
new file mode 100644
index 000..5282f44
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -0,0 +1,394 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nvidia GPU I2C controller Driver
+ *
+ * Copyright (C) 2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta 
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+/* I2C definitions */
+#define I2C_MST_CNTL   0x00
+#define I2C_MST_CNTL_GEN_START BIT(0)
+#define I2C_MST_CNTL_GEN_STOP  BIT(1)
+#define I2C_MST_CNTL_CMD_NONE  (0 << 2)
+#define I2C_MST_CNTL_CMD_READ  (1 << 2)
+#define I2C_MST_CNTL_CMD_WRITE (2 << 2)
+#define I2C_MST_CNTL_GEN_RAB   BIT(4)
+#define I2C_MST_CNTL_BURST_SIZE_SHIFT  6
+#define I2C_MST_CNTL_GEN_NACK  BIT(28)
+#define I2C_MST_CNTL_STATUSGENMASK(30, 29)
+#define I2C_MST_CNTL_STATUS_OKAY   (0 << 29)
+#define I2C_MST_CNTL_STATUS_NO_ACK (1 << 29)
+#define I2C_MST_CNTL_STATUS_TIMEOUT(2 << 29)
+#define I2C_MST_CNTL_STATUS_BUS_BUSY   (3 << 29)
+#define I2C

[PATCH v7 2/2] usb: typec: ucsi: add support for Cypress CCGx

2018-09-06 Thread Ajay Gupta
Latest NVIDIA GPU cards have a Cypress CCGx Type-C controller
over I2C interface.

This UCSI I2C driver uses I2C bus driver interface for communicating
with Type-C controller.

Signed-off-by: Ajay Gupta 
Reviewed-by: Andy Shevchenko 
Acked-by: Heikki Krogerus 
---
Changes from v1 -> v2
Fixed identation in drivers/usb/typec/ucsi/Kconfig
Changes from v2 -> v3
Fixed most of comments from Heikki
Rename ucsi_i2c_ccg.c -> ucsi_ccg.c
Changes from v3 -> v4
Fixed comments from Andy
Changes from v4 -> v5
Fixed comments from Andy
Changes from v5 -> v6
Fixed review comments from Greg 
Changes from v6 -> v7
None

 drivers/usb/typec/ucsi/Kconfig|  10 +
 drivers/usb/typec/ucsi/Makefile   |   2 +
 drivers/usb/typec/ucsi/ucsi_ccg.c | 382 ++
 3 files changed, 394 insertions(+)
 create mode 100644 drivers/usb/typec/ucsi/ucsi_ccg.c

diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig
index e36d6c7..7811888 100644
--- a/drivers/usb/typec/ucsi/Kconfig
+++ b/drivers/usb/typec/ucsi/Kconfig
@@ -23,6 +23,16 @@ config TYPEC_UCSI
 
 if TYPEC_UCSI
 
+config UCSI_CCG
+   tristate "UCSI Interface Driver for Cypress CCGx"
+   depends on I2C
+   help
+ This driver enables UCSI support on platforms that expose a
+ Cypress CCGx Type-C controller over I2C interface.
+
+ To compile the driver as a module, choose M here: the module will be
+ called ucsi_ccg.
+
 config UCSI_ACPI
tristate "UCSI ACPI Interface Driver"
depends on ACPI
diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile
index 7afbea5..2f4900b 100644
--- a/drivers/usb/typec/ucsi/Makefile
+++ b/drivers/usb/typec/ucsi/Makefile
@@ -8,3 +8,5 @@ typec_ucsi-y:= ucsi.o
 typec_ucsi-$(CONFIG_TRACING)   += trace.o
 
 obj-$(CONFIG_UCSI_ACPI)+= ucsi_acpi.o
+
+obj-$(CONFIG_UCSI_CCG) += ucsi_ccg.o
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
new file mode 100644
index 000..65292bf
--- /dev/null
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -0,0 +1,382 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * UCSI driver for Cypress CCGx Type-C controller
+ *
+ * Copyright (C) 2017-2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta 
+ *
+ * Some code borrowed from drivers/usb/typec/ucsi/ucsi_acpi.c
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include "ucsi.h"
+
+struct ucsi_ccg {
+   struct device *dev;
+   struct ucsi *ucsi;
+   struct ucsi_ppm ppm;
+   struct i2c_client *client;
+   int irq;
+};
+
+#define CCGX_I2C_RAB_DEVICE_MODE   0x00
+#define CCGX_I2C_RAB_READ_SILICON_ID   0x2
+#define CCGX_I2C_RAB_INTR_REG  0x06
+#define CCGX_I2C_RAB_FW1_VERSION   0x28
+#define CCGX_I2C_RAB_FW2_VERSION   0x20
+#define CCGX_I2C_RAB_UCSI_CONTROL  0x39
+#define CCGX_I2C_RAB_UCSI_CONTROL_STARTBIT(0)
+#define CCGX_I2C_RAB_UCSI_CONTROL_STOP BIT(1)
+#define CCGX_I2C_RAB_RESPONSE_REG  0x7E
+#define CCGX_I2C_RAB_UCSI_DATA_BLOCK   0xf000
+
+static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
+{
+   struct i2c_client *client = uc->client;
+   unsigned char *buf;
+   struct i2c_msg *msgs;
+   u32 rlen, rem_len = len;
+   int status;
+
+   buf = kzalloc(2, GFP_KERNEL);
+   if (!buf)
+   return -ENOMEM;
+
+   msgs = kcalloc(2, sizeof(struct i2c_msg), GFP_KERNEL);
+   if (!msgs) {
+   kfree(buf);
+   return -ENOMEM;
+   }
+
+   msgs[0].addr = client->addr;
+   msgs[0].len = 2;
+   msgs[0].buf = buf;
+   msgs[1].addr = client->addr;
+   msgs[1].flags = I2C_M_RD;
+
+   while (rem_len > 0) {
+   msgs[1].buf = &data[len - rem_len];
+   rlen = min_t(u16, rem_len, 4);
+   msgs[1].len = rlen;
+   put_unaligned_le16(rab, buf);
+   status = i2c_transfer(client->adapter, msgs, 2);
+   if (status < 0) {
+   dev_err(uc->dev, "i2c_transfer failed %d", status);
+   kfree(buf);
+   kfree(msgs);
+   return status;
+   }
+   rab += rlen;
+   rem_len -= rlen;
+   }
+
+   kfree(buf);
+   kfree(msgs);
+   return 0;
+}
+
+static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
+{
+   struct i2c_client *client = uc->client;
+   unsigned char *buf;
+   struct i2c_msg *msgs;
+   int status;
+
+   buf = kzalloc(2, GFP_KERNEL);
+   if (!buf)
+   re

RE: [PATCH v6 1/2] i2c: buses: add i2c bus driver for NVIDIA GPU

2018-09-06 Thread Ajay Gupta
>dev, "pcim_enable_device failed %d\n",
> >> status);
> >>> + return status;
> >>> + }
> >>> +
> >>> + pci_set_master(pdev);
> >>> +
> >>> + i2cd->regs = pcim_iomap(pdev, 0, 0);
> >>> + if (!i2cd->regs) {
> >>> + dev_err(&pdev->dev, "pcim_iomap failed\n");
> >>> + return -ENOMEM;
> >>> + }
> >>> +
> >>> + status = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
> >>> + if (status < 0) {
> >>> + dev_err(&pdev->dev, "pci_alloc_irq_vectors err %d\n",
> >> status);
> >>> + return status;
> >>> + }
> >>> +
> >>> + i2cd->do_start = true;
> >>> + mutex_init(&i2cd->mutex);
> >>> + enable_i2c_bus(i2cd);
> >>> +
> >>> + i2c_set_adapdata(&i2cd->adapter, i2cd);
> >>> + i2cd->adapter.owner = THIS_MODULE;
> >>> + strlcpy(i2cd->adapter.name, "NVIDIA GPU I2C adapter",
> >>> + sizeof(i2cd->adapter.name));
> >>> + i2cd->adapter.algo = &gpu_i2c_algorithm;
> >>> + i2cd->adapter.dev.parent = &pdev->dev;
> >>> + status = i2c_add_adapter(&i2cd->adapter);
> >>> + if (status < 0) {
> >>> + dev_err(&pdev->dev, "i2c_add_adapter failed %d\n", status);
> >>> + goto free_irq_vectors;
> >>> + }
> >>> +
> >>> + status = gpu_populate_client(i2cd, pdev->irq);
> >>> + if (status < 0) {
> >>> + dev_err(&pdev->dev, "gpu_populate_client failed %d\n",
> >> status);
> >>> + goto del_adapter;
> >>> + }
> >>> +
> >>> + return 0;
> >>> +
> >>> +del_adapter:
> >>> + i2c_del_adapter(&i2cd->adapter);
> >>> +free_irq_vectors:
> >>> + pci_free_irq_vectors(pdev);
> >>> + return status;
> >>> +}
> >>> +
> >>> +static void gpu_i2c_remove(struct pci_dev *pdev) {
> >>> + struct gpu_i2c_dev *i2cd = dev_get_drvdata(&pdev->dev);
> >>> +
> >>> + i2c_del_adapter(&i2cd->adapter);
> >>> + pci_free_irq_vectors(pdev);
> >>> +}
> >>> +
> >>> +static int gpu_i2c_resume(struct device *dev) {
> >>> + struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
> >>> +
> >>> + enable_i2c_bus(i2cd);
> >>> + return 0;
> >>> +}
> >>> +
> >>> +static int gpu_i2c_idle(struct device *dev) {
> >>> + struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
> >>> +
> >>> + if (!mutex_trylock(&i2cd->mutex)) {
> >>> + dev_info(dev, "-EBUSY\n");
> >>> + return -EBUSY;
> >>> + }
> >>> + mutex_unlock(&i2cd->mutex);
> >>> +
> >>> + return 0;
> >>> +}
> >>> +
> >>> +UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, NULL, gpu_i2c_resume,
> >>> +gpu_i2c_idle);
> >>> +
> >>> +static struct pci_driver gpu_i2c_driver = {
> >>> + .name   = "nvidia-gpu",
> >>> + .id_table   = gpu_i2c_ids,
> >>> + .probe  = gpu_i2c_probe,
> >>> + .remove = gpu_i2c_remove,
> >>> + .driver = {
> >>> + .pm = &gpu_i2c_driver_pm,
> >>> + },
> >>> +};
> >>> +
> >>> +module_pci_driver(gpu_i2c_driver);
> >>> +
> >>> +MODULE_AUTHOR("Ajay Gupta ");
> >>> +MODULE_DESCRIPTION("Nvidia GPU I2C controller Driver");
> >>> +MODULE_LICENSE("GPL v2");
> >>>
> >



RE: [PATCH v7 2/2] usb: typec: ucsi: add support for Cypress CCGx

2018-09-06 Thread Ajay Gupta
csi_ppm *ppm, struct ucsi_control
> > +*ctrl) {
> > +   struct ucsi_ccg *uc = container_of(ppm, struct ucsi_ccg, ppm);
> > +
> > +   ppm->data->ctrl.raw_cmd = ctrl->raw_cmd;
> > +   return ucsi_ccg_send_data(uc);
> > +}
> > +
> > +static irqreturn_t ccg_irq_handler(int irq, void *data) {
> > +   struct ucsi_ccg *uc = data;
> > +
> > +   ucsi_notify(uc->ucsi);
> > +
> > +   return IRQ_HANDLED;
> > +}
> > +
> > +static int ucsi_ccg_probe(struct i2c_client *client,
> > + const struct i2c_device_id *id)
> > +{
> > +   struct device *dev = &client->dev;
> > +   struct ucsi_ccg *uc;
> > +   int status;
> > +
> > +   uc = devm_kzalloc(dev, sizeof(*uc), GFP_KERNEL);
> > +   if (!uc)
> > +   return -ENOMEM;
> > +
> > +   uc->ppm.data = devm_kzalloc(dev, sizeof(struct ucsi_data),
> GFP_KERNEL);
> > +   if (!uc->ppm.data)
> > +   return -ENOMEM;
> > +
> > +   uc->ppm.cmd = ucsi_ccg_cmd;
> > +   uc->ppm.sync = ucsi_ccg_sync;
> > +   uc->dev = dev;
> > +   uc->client = client;
> > +
> > +   /* reset ccg device and initialize ucsi */
> > +   status = ucsi_ccg_init(uc);
> > +   if (status < 0) {
> > +   dev_err(uc->dev, "ucsi_ccg_init failed - %d\n", status);
> > +   return status;
> > +   }
> > +
> > +   uc->irq = client->irq;
> > +
> > +   status = devm_request_threaded_irq(dev, uc->irq, NULL,
> ccg_irq_handler,
> > +  IRQF_ONESHOT |
> IRQF_TRIGGER_HIGH,
> > +  dev_name(dev), uc);
> > +   if (status < 0) {
> > +   dev_err(uc->dev, "request_threaded_irq failed - %d\n",
> status);
> > +   return status;
> > +   }
> > +
> > +   uc->ucsi = ucsi_register_ppm(dev, &uc->ppm);
> > +   if (IS_ERR(uc->ucsi)) {
> > +   dev_err(uc->dev, "ucsi_register_ppm failed\n");
> > +   return PTR_ERR(uc->ucsi);
> > +   }
> > +
> > +   i2c_set_clientdata(client, uc);
> > +   return 0;
> > +}
> > +
> > +static int ucsi_ccg_remove(struct i2c_client *client) {
> > +   struct ucsi_ccg *uc = i2c_get_clientdata(client);
> > +
> > +   ucsi_unregister_ppm(uc->ucsi);
> > +
> > +   return 0;
> > +}
> > +
> > +static const struct i2c_device_id ucsi_ccg_device_id[] = {
> > +   {"ccgx-ucsi", 0},
> > +   {}
> > +};
> > +MODULE_DEVICE_TABLE(i2c, ucsi_ccg_device_id);
> > +
> > +static struct i2c_driver ucsi_ccg_driver = {
> > +   .driver = {
> > +   .name = "ucsi_ccg",
> > +   },
> > +   .probe = ucsi_ccg_probe,
> > +   .remove = ucsi_ccg_remove,
> > +   .id_table = ucsi_ccg_device_id,
> > +};
> > +
> > +module_i2c_driver(ucsi_ccg_driver);
> > +
> > +MODULE_AUTHOR("Ajay Gupta ");
> > +MODULE_DESCRIPTION("UCSI driver for Cypress CCGx Type-C controller");
> > +MODULE_LICENSE("GPL v2");
> >



[PATCH v8 2/2] usb: typec: ucsi: add support for Cypress CCGx

2018-09-06 Thread Ajay Gupta
Latest NVIDIA GPU cards have a Cypress CCGx Type-C controller
over I2C interface.

This UCSI I2C driver uses I2C bus driver interface for communicating
with Type-C controller.

Signed-off-by: Ajay Gupta 
---
Changes from v1 -> v2
Fixed identation in drivers/usb/typec/ucsi/Kconfig
Changes from v2 -> v3
Fixed most of comments from Heikki
Rename ucsi_i2c_ccg.c -> ucsi_ccg.c
Changes from v3 -> v4
Fixed comments from Andy
Changes from v4 -> v5
Fixed comments from Andy
Changes from v5 -> v6
Fixed review comments from Greg 
Changes from v6 -> v7
None
Changes from v7 -> v8
Fixed review comments from Peter 
- Removed empty STOP message
- Using stack memory for i2c_transfer()

 drivers/usb/typec/ucsi/Kconfig|  10 ++
 drivers/usb/typec/ucsi/Makefile   |   2 +
 drivers/usb/typec/ucsi/ucsi_ccg.c | 335 ++
 3 files changed, 347 insertions(+)
 create mode 100644 drivers/usb/typec/ucsi/ucsi_ccg.c

diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig
index e36d6c7..7811888 100644
--- a/drivers/usb/typec/ucsi/Kconfig
+++ b/drivers/usb/typec/ucsi/Kconfig
@@ -23,6 +23,16 @@ config TYPEC_UCSI
 
 if TYPEC_UCSI
 
+config UCSI_CCG
+   tristate "UCSI Interface Driver for Cypress CCGx"
+   depends on I2C
+   help
+ This driver enables UCSI support on platforms that expose a
+ Cypress CCGx Type-C controller over I2C interface.
+
+ To compile the driver as a module, choose M here: the module will be
+ called ucsi_ccg.
+
 config UCSI_ACPI
tristate "UCSI ACPI Interface Driver"
depends on ACPI
diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile
index 7afbea5..2f4900b 100644
--- a/drivers/usb/typec/ucsi/Makefile
+++ b/drivers/usb/typec/ucsi/Makefile
@@ -8,3 +8,5 @@ typec_ucsi-y:= ucsi.o
 typec_ucsi-$(CONFIG_TRACING)   += trace.o
 
 obj-$(CONFIG_UCSI_ACPI)+= ucsi_acpi.o
+
+obj-$(CONFIG_UCSI_CCG) += ucsi_ccg.o
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
new file mode 100644
index 000..387b6fd
--- /dev/null
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * UCSI driver for Cypress CCGx Type-C controller
+ *
+ * Copyright (C) 2017-2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta 
+ *
+ * Some code borrowed from drivers/usb/typec/ucsi/ucsi_acpi.c
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include "ucsi.h"
+
+struct ucsi_ccg {
+   struct device *dev;
+   struct ucsi *ucsi;
+   struct ucsi_ppm ppm;
+   struct i2c_client *client;
+   int irq;
+};
+
+#define CCGX_I2C_RAB_DEVICE_MODE   0x00
+#define CCGX_I2C_RAB_READ_SILICON_ID   0x2
+#define CCGX_I2C_RAB_INTR_REG  0x06
+#define CCGX_I2C_RAB_FW1_VERSION   0x28
+#define CCGX_I2C_RAB_FW2_VERSION   0x20
+#define CCGX_I2C_RAB_UCSI_CONTROL  0x39
+#define CCGX_I2C_RAB_UCSI_CONTROL_STARTBIT(0)
+#define CCGX_I2C_RAB_UCSI_CONTROL_STOP BIT(1)
+#define CCGX_I2C_RAB_RESPONSE_REG  0x7E
+#define CCGX_I2C_RAB_UCSI_DATA_BLOCK   0xf000
+
+static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
+{
+   struct i2c_client *client = uc->client;
+   unsigned char buf[2];
+   struct i2c_msg msgs[] = {
+   {
+   .addr   = client->addr,
+   .flags  = 0x0,
+   .len= 0x2,
+   .buf= buf,
+   },
+   {
+   .addr   = client->addr,
+   .flags  = I2C_M_RD,
+   .buf= data,
+   },
+   };
+   u32 rlen, rem_len = len;
+   int status;
+
+   while (rem_len > 0) {
+   msgs[1].buf = &data[len - rem_len];
+   rlen = min_t(u16, rem_len, 4);
+   msgs[1].len = rlen;
+   put_unaligned_le16(rab, buf);
+   status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+   if (status < 0) {
+   dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+   return status;
+   }
+   rab += rlen;
+   rem_len -= rlen;
+   }
+
+   return 0;
+}
+
+static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
+{
+   struct i2c_client *client = uc->client;
+   unsigned char buf[2];
+   struct i2c_msg msgs[] = {
+   {
+   .addr   = client->addr,
+   

[PATCH v8 1/2] i2c: buses: add i2c bus driver for NVIDIA GPU

2018-09-06 Thread Ajay Gupta
Latest NVIDIA GPU card has USB Type-C interface. There is a
Type-C controller which can be accessed over I2C.

This driver adds I2C bus driver to communicate with Type-C controller.
I2C client driver will be part of USB Type-C UCSI driver.

Signed-off-by: Ajay Gupta 
Reviewed-by: Andy Shevchenko 
Reviewed-by: Heikki Krogerus 
---
Changes from v1 -> v2
None
Changes from v2 -> v3
Fixed review comments from Andy and Thierry
Rename i2c-gpu.c -> i2c-nvidia-gpu.c
Changes from v3 -> v4
Fixed review comments from Andy
Changes from v4 -> v5
Fixed review comments from Andy
Changes from v5 -> v6
None 
Changes from v6 -> v7 -> v8
Fixed review comments from Peter 
- Add implicit STOP for last write message
- Add i2c_adapter_quirks with max_read_len and
  I2C_AQ_COMB flags

 Documentation/i2c/busses/i2c-nvidia-gpu |  18 ++
 MAINTAINERS |   7 +
 drivers/i2c/busses/Kconfig  |   9 +
 drivers/i2c/busses/Makefile |   1 +
 drivers/i2c/busses/i2c-nvidia-gpu.c | 400 
 5 files changed, 435 insertions(+)
 create mode 100644 Documentation/i2c/busses/i2c-nvidia-gpu
 create mode 100644 drivers/i2c/busses/i2c-nvidia-gpu.c

diff --git a/Documentation/i2c/busses/i2c-nvidia-gpu 
b/Documentation/i2c/busses/i2c-nvidia-gpu
new file mode 100644
index 000..31884d2
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-nvidia-gpu
@@ -0,0 +1,18 @@
+Kernel driver i2c-nvidia-gpu
+
+Datasheet: not publicly available.
+
+Authors:
+   Ajay Gupta 
+
+Description
+---
+
+i2c-nvidia-gpu is a driver for I2C controller included in NVIDIA Turing
+and later GPUs and it is used to communicate with Type-C controller on GPUs.
+
+If your 'lspci -v' listing shows something like the following,
+
+01:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device 1ad9 (rev a1)
+
+then this driver should support the I2C controller of your GPU.
diff --git a/MAINTAINERS b/MAINTAINERS
index 9ad052a..2d1c5a1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6797,6 +6797,13 @@ L:   linux-a...@vger.kernel.org
 S: Maintained
 F: drivers/i2c/i2c-core-acpi.c
 
+I2C CONTROLLER DRIVER FOR NVIDIA GPU
+M: Ajay Gupta 
+L: linux-...@vger.kernel.org
+S: Maintained
+F: Documentation/i2c/busses/i2c-nvidia-gpu
+F: drivers/i2c/busses/i2c-nvidia-gpu.c
+
 I2C MUXES
 M: Peter Rosin 
 L: linux-...@vger.kernel.org
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 451d4ae..eed827b 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -224,6 +224,15 @@ config I2C_NFORCE2_S4985
  This driver can also be built as a module.  If so, the module
  will be called i2c-nforce2-s4985.
 
+config I2C_NVIDIA_GPU
+   tristate "NVIDIA GPU I2C controller"
+   depends on PCI
+   help
+ If you say yes to this option, support will be included for the
+ NVIDIA GPU I2C controller which is used to communicate with the GPU's
+ Type-C controller. This driver can also be built as a module called
+ i2c-nvidia-gpu.
+
 config I2C_SIS5595
tristate "SiS 5595"
depends on PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 18b26af..d499813 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -140,5 +140,6 @@ obj-$(CONFIG_I2C_SIBYTE)+= i2c-sibyte.o
 obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o
 obj-$(CONFIG_SCx200_ACB)   += scx200_acb.o
 obj-$(CONFIG_I2C_FSI)  += i2c-fsi.o
+obj-$(CONFIG_I2C_NVIDIA_GPU)   += i2c-nvidia-gpu.o
 
 ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
new file mode 100644
index 000..4816a31
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -0,0 +1,400 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nvidia GPU I2C controller Driver
+ *
+ * Copyright (C) 2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta 
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+/* I2C definitions */
+#define I2C_MST_CNTL   0x00
+#define I2C_MST_CNTL_GEN_START BIT(0)
+#define I2C_MST_CNTL_GEN_STOP  BIT(1)
+#define I2C_MST_CNTL_CMD_NONE  (0 << 2)
+#define I2C_MST_CNTL_CMD_READ  (1 << 2)
+#define I2C_MST_CNTL_CMD_WRITE (2 << 2)
+#define I2C_MST_CNTL_GEN_RAB   BIT(4)
+#define I2C_MST_CNTL_BURST_SIZE_SHIFT  6
+#define I2C_MST_CNTL_GEN_NACK  BIT(28)
+#define I2C_MST_CNTL_STATUSGENMASK(30, 29)
+#define I2C_MST_CNTL_STATUS_OKAY   (0 << 29)
+#define I2C_MST_CNTL_STATUS_NO_ACK  

[PATCH v9 1/2] i2c: buses: add i2c bus driver for NVIDIA GPU

2018-09-06 Thread Ajay Gupta
Latest NVIDIA GPU card has USB Type-C interface. There is a
Type-C controller which can be accessed over I2C.

This driver adds I2C bus driver to communicate with Type-C controller.
I2C client driver will be part of USB Type-C UCSI driver.

Signed-off-by: Ajay Gupta 
Reviewed-by: Andy Shevchenko 
Reviewed-by: Heikki Krogerus 
---
Changes from v1 -> v2
None
Changes from v2 -> v3
Fixed review comments from Andy and Thierry
Rename i2c-gpu.c -> i2c-nvidia-gpu.c
Changes from v3 -> v4
Fixed review comments from Andy
Changes from v4 -> v5
Fixed review comments from Andy
Changes from v5 -> v6
None 
Changes from v6 -> v7 -> v8
Fixed review comments from Peter 
- Add implicit STOP for last write message
- Add i2c_adapter_quirks with max_read_len and
  I2C_AQ_COMB flags
Changes from v8 -> v9
Fixed review comments from Peter
- Drop do_start flag
- Use i2c_8bit_addr_from_msg()

 Documentation/i2c/busses/i2c-nvidia-gpu |  18 ++
 MAINTAINERS |   7 +
 drivers/i2c/busses/Kconfig  |   9 +
 drivers/i2c/busses/Makefile |   1 +
 drivers/i2c/busses/i2c-nvidia-gpu.c | 396 
 5 files changed, 431 insertions(+)
 create mode 100644 Documentation/i2c/busses/i2c-nvidia-gpu
 create mode 100644 drivers/i2c/busses/i2c-nvidia-gpu.c

diff --git a/Documentation/i2c/busses/i2c-nvidia-gpu 
b/Documentation/i2c/busses/i2c-nvidia-gpu
new file mode 100644
index 000..31884d2
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-nvidia-gpu
@@ -0,0 +1,18 @@
+Kernel driver i2c-nvidia-gpu
+
+Datasheet: not publicly available.
+
+Authors:
+   Ajay Gupta 
+
+Description
+---
+
+i2c-nvidia-gpu is a driver for I2C controller included in NVIDIA Turing
+and later GPUs and it is used to communicate with Type-C controller on GPUs.
+
+If your 'lspci -v' listing shows something like the following,
+
+01:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device 1ad9 (rev a1)
+
+then this driver should support the I2C controller of your GPU.
diff --git a/MAINTAINERS b/MAINTAINERS
index 9ad052a..2d1c5a1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6797,6 +6797,13 @@ L:   linux-a...@vger.kernel.org
 S: Maintained
 F: drivers/i2c/i2c-core-acpi.c
 
+I2C CONTROLLER DRIVER FOR NVIDIA GPU
+M: Ajay Gupta 
+L: linux-...@vger.kernel.org
+S: Maintained
+F: Documentation/i2c/busses/i2c-nvidia-gpu
+F: drivers/i2c/busses/i2c-nvidia-gpu.c
+
 I2C MUXES
 M: Peter Rosin 
 L: linux-...@vger.kernel.org
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 451d4ae..eed827b 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -224,6 +224,15 @@ config I2C_NFORCE2_S4985
  This driver can also be built as a module.  If so, the module
  will be called i2c-nforce2-s4985.
 
+config I2C_NVIDIA_GPU
+   tristate "NVIDIA GPU I2C controller"
+   depends on PCI
+   help
+ If you say yes to this option, support will be included for the
+ NVIDIA GPU I2C controller which is used to communicate with the GPU's
+ Type-C controller. This driver can also be built as a module called
+ i2c-nvidia-gpu.
+
 config I2C_SIS5595
tristate "SiS 5595"
depends on PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 18b26af..d499813 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -140,5 +140,6 @@ obj-$(CONFIG_I2C_SIBYTE)+= i2c-sibyte.o
 obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o
 obj-$(CONFIG_SCx200_ACB)   += scx200_acb.o
 obj-$(CONFIG_I2C_FSI)  += i2c-fsi.o
+obj-$(CONFIG_I2C_NVIDIA_GPU)   += i2c-nvidia-gpu.o
 
 ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c 
b/drivers/i2c/busses/i2c-nvidia-gpu.c
new file mode 100644
index 000..4a63a4e4
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nvidia-gpu.c
@@ -0,0 +1,396 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nvidia GPU I2C controller Driver
+ *
+ * Copyright (C) 2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta 
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+/* I2C definitions */
+#define I2C_MST_CNTL   0x00
+#define I2C_MST_CNTL_GEN_START BIT(0)
+#define I2C_MST_CNTL_GEN_STOP  BIT(1)
+#define I2C_MST_CNTL_CMD_NONE  (0 << 2)
+#define I2C_MST_CNTL_CMD_READ  (1 << 2)
+#define I2C_MST_CNTL_CMD_WRITE (2 << 2)
+#define I2C_MST_CNTL_GEN_RAB   BIT(4)
+#define I2C_MST_CNTL_BURST_SIZE_SHIFT  6
+#define I2C_MST_CNTL_GEN_NACK  BIT(28)
+#define I2C_MST_CNTL_STATUS

[PATCH v9 2/2] usb: typec: ucsi: add support for Cypress CCGx

2018-09-06 Thread Ajay Gupta
Latest NVIDIA GPU cards have a Cypress CCGx Type-C controller
over I2C interface.

This UCSI I2C driver uses I2C bus driver interface for communicating
with Type-C controller.

Signed-off-by: Ajay Gupta 
Reviewed-by: Andy Shevchenko 
Acked-by: Heikki Krogerus 
---
Changes from v1 -> v2
Fixed identation in drivers/usb/typec/ucsi/Kconfig
Changes from v2 -> v3
Fixed most of comments from Heikki
Rename ucsi_i2c_ccg.c -> ucsi_ccg.c
Changes from v3 -> v4
Fixed comments from Andy
Changes from v4 -> v5
Fixed comments from Andy
Changes from v5 -> v6
Fixed review comments from Greg 
Changes from v6 -> v7
None
Changes from v7 -> v8
Fixed review comments from Peter 
- Removed empty STOP message
- Using stack memory for i2c_transfer()
Changes from v8 -> v9
None

 drivers/usb/typec/ucsi/Kconfig|  10 ++
 drivers/usb/typec/ucsi/Makefile   |   2 +
 drivers/usb/typec/ucsi/ucsi_ccg.c | 335 ++
 3 files changed, 347 insertions(+)
 create mode 100644 drivers/usb/typec/ucsi/ucsi_ccg.c

diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig
index e36d6c7..7811888 100644
--- a/drivers/usb/typec/ucsi/Kconfig
+++ b/drivers/usb/typec/ucsi/Kconfig
@@ -23,6 +23,16 @@ config TYPEC_UCSI
 
 if TYPEC_UCSI
 
+config UCSI_CCG
+   tristate "UCSI Interface Driver for Cypress CCGx"
+   depends on I2C
+   help
+ This driver enables UCSI support on platforms that expose a
+ Cypress CCGx Type-C controller over I2C interface.
+
+ To compile the driver as a module, choose M here: the module will be
+ called ucsi_ccg.
+
 config UCSI_ACPI
tristate "UCSI ACPI Interface Driver"
depends on ACPI
diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile
index 7afbea5..2f4900b 100644
--- a/drivers/usb/typec/ucsi/Makefile
+++ b/drivers/usb/typec/ucsi/Makefile
@@ -8,3 +8,5 @@ typec_ucsi-y:= ucsi.o
 typec_ucsi-$(CONFIG_TRACING)   += trace.o
 
 obj-$(CONFIG_UCSI_ACPI)+= ucsi_acpi.o
+
+obj-$(CONFIG_UCSI_CCG) += ucsi_ccg.o
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c 
b/drivers/usb/typec/ucsi/ucsi_ccg.c
new file mode 100644
index 000..387b6fd
--- /dev/null
+++ b/drivers/usb/typec/ucsi/ucsi_ccg.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * UCSI driver for Cypress CCGx Type-C controller
+ *
+ * Copyright (C) 2017-2018 NVIDIA Corporation. All rights reserved.
+ * Author: Ajay Gupta 
+ *
+ * Some code borrowed from drivers/usb/typec/ucsi/ucsi_acpi.c
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include "ucsi.h"
+
+struct ucsi_ccg {
+   struct device *dev;
+   struct ucsi *ucsi;
+   struct ucsi_ppm ppm;
+   struct i2c_client *client;
+   int irq;
+};
+
+#define CCGX_I2C_RAB_DEVICE_MODE   0x00
+#define CCGX_I2C_RAB_READ_SILICON_ID   0x2
+#define CCGX_I2C_RAB_INTR_REG  0x06
+#define CCGX_I2C_RAB_FW1_VERSION   0x28
+#define CCGX_I2C_RAB_FW2_VERSION   0x20
+#define CCGX_I2C_RAB_UCSI_CONTROL  0x39
+#define CCGX_I2C_RAB_UCSI_CONTROL_STARTBIT(0)
+#define CCGX_I2C_RAB_UCSI_CONTROL_STOP BIT(1)
+#define CCGX_I2C_RAB_RESPONSE_REG  0x7E
+#define CCGX_I2C_RAB_UCSI_DATA_BLOCK   0xf000
+
+static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
+{
+   struct i2c_client *client = uc->client;
+   unsigned char buf[2];
+   struct i2c_msg msgs[] = {
+   {
+   .addr   = client->addr,
+   .flags  = 0x0,
+   .len= 0x2,
+   .buf= buf,
+   },
+   {
+   .addr   = client->addr,
+   .flags  = I2C_M_RD,
+   .buf= data,
+   },
+   };
+   u32 rlen, rem_len = len;
+   int status;
+
+   while (rem_len > 0) {
+   msgs[1].buf = &data[len - rem_len];
+   rlen = min_t(u16, rem_len, 4);
+   msgs[1].len = rlen;
+   put_unaligned_le16(rab, buf);
+   status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+   if (status < 0) {
+   dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+   return status;
+   }
+   rab += rlen;
+   rem_len -= rlen;
+   }
+
+   return 0;
+}
+
+static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
+{
+   struct i2c_client *client = uc->client;
+   unsigned char buf[2];
+   struct i2c_msg msgs[] = {
+   

  1   2   3   >