ocpbus(4)

M. Warner Losh imp at bsdimp.com
Fri Dec 28 17:22:12 PST 2007


In message: <1B0F37B8-D492-4E15-82A8-704243E67E90 at juniper.net>
            Marcel Moolenaar <marcelm at juniper.net> writes:
: On Dec 28, 2007, at 3:32 PM, M. Warner Losh wrote:
: 
: > The usb driver on atmel needs to manipulate the clock generator when
: > it is attached to generate the 48MHz needed for the USB devices.
: > However, when the driver isn't present in the kernel, the right thing
: > to do is to keep this clock off because it uses power.  How could this
: > be done generically?
: 
: The first important part here is whether the USB driver needs
: to know about the generator. For uart(4) the ocpbus handshake
: already includes an IVAR for the clock, so let's reuse that
: for USB. When the clock IVAR doesn't exist, the USB driver does
: not need to worry about the clock (default). If the clock IVAR
: exists, it returns something that tells the USB driver to
: program the generator.

The usb host adapter drivers could care less about the generator, or
if other platform specific things need to happen.  It is setup such
that the bus specific attachment routines do whatever dirtywork is
necessary to get the resources allocated and the chip setup in
specific ways.  Putting a lot of this into one attachment likely will
lead to lots of hacks for each platform infecting the 'generic' opcbus
attachment.

: What that something is, depends on whether the generator has a
: driver attached to it, or whether the clock is more platform
: specific than USB host controller specific.
:
: Let's assume the generator has a driver attached to it. The
: clock IVAR can then return the device_t of that driver and by
: means of a well-defined handshake (say a KOBJ I/F) the USB
: driver can tell the CG driver to enable the clock.

Can we come up with an interface that covers all the possible
arrangements of this sort of thing?  Would the specific ocpbus
implementation need to provide it?  Would it go up to the nexus?
There's quite a bit of variation in what is needed for usb.  It varies
from setting up clocks (which might be something we could make
relatively generic), to setting GPIOs to enable power on the
connector.

: If there's no driver attached to the generator, then the
: ocpbus attachment can pass resource information to the USB
: driver by way of a second RID. This then is used by the
: USB driver (ocpbus specific code) to program the generator.
:
: Of course, when the generator is within the USB resource
: range, it can be done from within the ocpbus attach function
: with the one resource assigned to the device. The IVAR then
: simply enables some code or another.

The generator isn't within the usb range  It is in another logical
part of the chip.

: Another way is have a "global" platform function for this
: that is called from the ocpbus attach function. That function
: can be a stub on platforms that have the same USB driver, but
: that do not have the generator.

All these ad-hoc solutions seem to me to make writing the attachments
harder.  I don't think they are something that can be made generic.

: > On the xscale port, there's support for the compact flash that lives
: > on many of them.  There's a number of chip-specific and board-specific
: > hacks that must happen in order for the generic driver to work.
: 
: This may be done using KOBJ interfaces.
: 
: I wrote a CFI driver and you can abstract the differences
: using KOBJ methods while still having a single driver.
: This is much akin to uart(4).

I guess what's at the other end of the kobj that worries me.

: > On the mips platform there are at least two flavors of 16550-like
: > uarts present.  One requires 32-bit access that's shifted 3 and the
: > other 64-bit access that's shifted 4.
: 
: Register shifting is already present in the uart(4) driver
: and information about it comes from the bus attachment. This
: does not mean that the uart(4) driver does 32- or 64-bit
: I/O. It always does 8-bit I/O. It's probably not a good idea
: to add support for 32-bit or 64-bit I/O to uart(4), unless
: we handle it as a separate hardware driver (the ns8250 is
: defined to use 8-bit I/O, so if that's not possible, it's
: not a ns8250 class UART).
: It's likely to be a platform or bus property, so it can all
: be handled naturally with the bus access functions. (i.e.
: implement the 1-byte access functions using 32- or 64-bit
: loads/stores).

how does the generic bus know how to set these device specific flags?

: > The SPI, and MMC drivers need to interact with the chip selects the
: > chip offers.  The manner of these interactions varies based on the
: > underlying SoC.
: 
: Either special drivers or otherwise a KOBJ interface to
: abstract it and use the ocpbus' DEVCLASS to select the
: KOBJ class (like uart(4)).

I'm not sure this is reasonable.  Maybe we should code up something to
see exactly how hard it would be.  This sounds like a lot of extra
work for not a lot of benefit.

: > Right now, all of these situations are dealt with by having a bit of
: > code in a specific attachment cope.
: 
: Right. All these bits of code can be triggered by
: information that comes from the bus. The uart(4) register
: shift comes from the bus (when uart(4) is a child of
: puc(4) or scc(4)) or is hardcoded (sparc64 ebus or sbus).
: 
: It's easy to expose that information through a single
: ocpbus handshake that includes information about the
: clock and register shift for UARTs.

How does ocpbus know about these things if it is generic?

: > : > Am I understanding your proposal correctly?  I can't see how  
: > else it
: > : > would work if this isn't the case, but if you have some clever  
: > scheme,
: > : > I'd be interested.
: > :
: > : No, this is more or less the gist of it. The type and id
: > : can be chosen in any way we like, including using the type
: > : as the id. The abstract bus driver does not need to know
: > : anything other than maybe translate a table into a newbus
: > : hierarchy and using the type/id combination to flag a
: > : child.
: >
: > How does this abstract driver know about the children to add?  Or
: > rather, how were you envisioning it getting the table it needed?
: 
: That's not part of the ocpbus definition. It only defines
: the handshake between a bus and the bus attachment. In some
: cases you can put it all in nexus. In other cases you create
: a new bus driver that implements the handshake and has its
: own way of enumerating devices.

I'd imagine that typically you'd need to have it not be in nexus based
on my experience with arm.

: > : Any newbus node that implements the ocpbus handshake is
: > : then automatically an ocpbus driver even though there's
: > : no mention of how it obtains the device information. As
: > : I said before: it's about avoiding the flurry of bus
: > : attachments, not about dictating how devices are
: > : enumerated.
: >
: > I agree that's a noble goal, and maybe we can avoid it in many cases,
: > but not in all cases.  I just don't think having a large enumeration
: > table to make this work is worth the effort of maintaining it.  When
: > you go to add a new ocpbus driver, you need to touch additional places
: > than the direct method.
: 
: How so?

If you had a string that's the device to attach in the table, then you
wouldn't have to edit ocpbusvar.h, or whatever file defined the
enumeration, every time you added new devices that could attach to
ocpbus.

: > Now, apart from enumeration, I think that having a good, well known
: > protocol would be good.  I'm still a little unclear how one would
: > communicate some of the stuff to the drivers, but I'm doing a p4 sync
: > right now to get the e500 branch so I can take a look at what's there.
: 
: For uart(4) we currently have:
: 
: 	static int
: 	uart_ocp_probe(device_t dev)
: 	{
: 		device_t parent;
: 		struct uart_softc *sc;
: 		uintptr_t clock, devtype;
: 		int error;
: 
: 		parent = device_get_parent(dev);
: 
: 		error = BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_DEVTYPE, &devtype);
: 		if (error)
: 			return (error);
: 		if (devtype != OCPBUS_DEVTYPE_UART)
: 			return (ENXIO);
: 
: 		sc = device_get_softc(dev);
: 		sc->sc_class = &uart_ns8250_class;	/*1*/
: 
: 		if (BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_CLOCK, &clock))
: 			clock = 0;
: 		return (uart_bus_probe(dev, 0, clock, 0, 0));	/*2*/
: 	}
: 
: At /*1*/ we can add support for a DEVCLASS to handle non-ns8250
: UARTs and at /*2*/ we can add support for REGSHIFT. All based
: on demand and all well-defined so that it's easy to replace an
: existing driver with another.

This side of things isn't too horrible, but the sending side is what I
worry about.  How does the ocpbus know about these details and remain
generic?

Warner


More information about the freebsd-embedded mailing list