Broadcom DQM

Broadcom DQM's are hardware FIFO's into which data words can be pushed by a
producer and popped by a consumer. There can only be 1 producer and 1 consumer
for a DQM. For each DQM the number of words per push/pop (element) is
configurable as is the depth of the DQM.

DQM's are part of a larger hardware block containing L2 interrupt control to
the CPU and thus are represented as a DQM device named for the larger hardware
block (i.e. GFAP DQM's, G2U DQM's, DFAP DQM's, etc). Within the DQM device
the individual DQM's are grouped into banks of 32 with each bank containing a
set of mask, status, interrupt, etc registers.

The DQM's can be configured by the DQM driver during driver probe or they can
be configured outside outside of Linux in which case the driver queries the
hardware to determine the configuration. The number of words/element and the
depth of the DQM is limited by internal SRAM (QSM) available on the device
as well as some hard limits imposed by register field sizes. Some DQM's can
only use QSM to store the FIFO elements while others can offload their FIFO
elements to DDR using FPM buffers managed by the DQM hardware.

Required properties:

- compatible:
    Must be "brcm,dqm"

- reg:
    Defines the base and range of the I/O address space of the device
    containing the DQM registers.
    If 2nd cell is defined then it points to base and range of the I/O address
    space of the device containing the DQM data registers

- dev-name:
    Unique device name

- cfg-offset:
    Byte offset from reg of the DQM config register.

- q-ctl-base-offset:
    Byte offset from reg of the queue control register block for the first DQM
    of each bank. This is not required if restricted-access defined

- q-data-base-offset:
    Byte offset from reg of the queue data register block for the first DQM of
    each bank.

- q-status-base-offset:
    Byte offset from reg of the queue status register for the first DQM of
    each bank.

- q-mib-base-offset:
    Byte offset from reg of the queue mib register for the first DQM of
    each bank.

- q-count:
    The total number of DQM's supported by this device.


Optional properties:

- offload
    Supports offload DQM's.

- fpm-alloc-offset:
    Byte offset from reg of the FPM allocation register to use for each bank.
    This register is required if the device supports offload DQM's.

- token-offset:

- q-tmr-base-offset:
    Byte offset from reg of the queue timer register block for the first DQM of
    each bank.

- cfg-qsm:
    Set to 1 to indicate that the driver should configure the DQM's for this
    device when it is probed. When this is set the #qsm-alloc-cells and
    qsm-allocation properties are required.

- qsm-size:
    The amount of QSM available on the device in 32-bit words.

- legacy-irq
    Support for legacy interrupt controller.

- live-irq
    Support for interrupt per DQM.

- ext-irq
    Support for external interrupt controller.

- restricted-access
    In this mode, certain cfg and ctl registers are not accessed

Legacy/Ext IRQ interrupt controller child node required properties
- interrupt-controller
    Defines child node as interrupt controller

- interrupts:
    The interrupt of the device containing the DQM's.

#interrupt-cells
    1

- interrupt-parent:
    phandle of the parent interrupt controller.

- l1-irq-mask-offset:
    Byte offset from reg of the register containing the top-level mask
    bits for each DQM bank.

- l1-irq-status-offset:
    Byte offset from reg of the register containing the top-level status
    bits for each DQM bank.

- l1-irq-dqm-mask:
    The mask for each bank that is required to enable the interrupt for the
    bank.

- lwm-irq-mask-offset:
    Byte offset from reg of the low watermark IRQ mask register for each bank.
    The low waterrmark is used to interrupt when the amount of elements in
    the DQM falls below the low watermark threshold.
    For ext irq case, this array of size 3 which has byte offset for
    mask, set and clear registers.

- lwm-irq-status-offset:
    Byte offset from reg of the low watermark IRQ status register for each
    bank.

- ne-irq-mask-offset:
    Byte offset from reg of the not empty IRQ mask register for each bank.
    For ext irq case, this array of size 3 which has byte offset for
    mask, set and clear registers.

- ne-irq-status-offset:
    Byte offset from reg of the not empty IRQ status register for each bank.

- ne-status-offset:
    Byte offset from reg of the not empty status register for each bank.

- hwm-irq-mask-offset:
    Byte offset of the high watermark IRQ mask register for each bank.
    The high waterrmark is used to interrupt when the amount of elements in
    the DQM rises above the high watermark threshold.
    For ext irq case, this array of size 3 which has byte offset for
    mask, set and clear registers.

- hwm-irq-status-offset:
    Byte offset of the high watermark IRQ status register for each bank.

- tmr-irq-mask-offset:
    Byte offset of the DQM timer IRQ mask register for each bank. When
    supported by the hardware the queue timer is used to interrupt when
    the amount of elements in the DQM is non-zero for a period of time. This
    is used in conjunction with the high watermark to coallesce interrupts.
    For ext irq case, this array of size 3 which has byte offset for
    mask, set and clear registers.

- tmr-irq-status-offset:
    Byte offset of the DQM timer IRQ status register for each bank.


Queue configuration child node required properties:
    - qname
        Queue name.
    - id
        Indicates the 0-based index of the DQM to configure.

Queue configuration child node properties if required to configure it:
    - words
        The number of 32-bit words that must be pushed/popped for each element
        in the DQM.
    - depth
        The maximum number of elements that the DQM can hold.
    - non-offload
        Whether the DQM should offload (1) to DDR or remain within QSM (0). The
        underlying DQM hardware must support offloading if set to 1. Offload
        DQM's require 1024 bytes of QSM so it only makes sense to offload a
        DQM if #words/element * 4 bytes/word * # elements > 1024.
    - lwm
        The low watermark threshold represented as the number of elements in
        the DQM.
    - hwm
        The high watermark threshold represented as the number of elements in
        the DQM.
    - timeout
        Timeout in milliseconds. Once the first element is pushed the timer
        will begin counting. If the high watermark threshold is not reached
        prior to the timeout being reached an interrupt will fire. This is used
        to coallesce interrupts from a DQM. THe DQM hardware must have DQM
        timer and high watermark support.

Queue configuration child node properties if required to send/receive data:
    - interrupt-parent:
        phandle of the parent interrupt controller.
    - interrupts:
        0 to 31.

Queue configuration child node properties for live IRQ if required to send/receive data:
    - live-irq-status-offset
       Byte offset from reg of the register containing the top-level status
       bits for all DQMs.
    - live-irq-mask-offset
       Array of size 3, which has byte offset from reg of the NE/LWM/HWM/Timeout
	IRQ mask, set and clear registers for each DQM.


Legacy IRQ example:

	dqm: dqm@d3800000 {
		compatible = "brcm,dqm";
		reg = <0x0 0xd3800000 0x0 0xa580>;
		offload;
		dev-name = "cpucomm";
		fpm-alloc-offset	= <0x1df4 0x1df4 0x1df4>;
		token-offset		= <0x1400>;
		cfg-offset		= <0x1c00 0x1c00 0x1c00>;
		q-ctl-base-offset	= <0x8000 0x8400 0x8800>;
		q-tmr-base-offset	= <0x2000 0x2100 0x2200>;
		q-data-base-offset	= <0x9000 0x9400 0x9800>;
		q-status-base-offset	= <0x7400 0x7480 0x7500>;
		q-mib-base-offset	= <0xa000 0xa200 0xa400>;
		q-count			= <96>;
		cfg-qsm			= <1>;
		qsm-size		= <0x2fc0>;	/* Bx and beyond top 256 bytes reserved for random seed created by bootrom */

		legacy-irq;
		dqmintc0: dqmintc0 {
			interrupts = <0 128 0>;
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <0x1>;
			l1-irq-mask-offset	= <0x0050>;
			l1-irq-status-offset	= <0x0054>;
			l1-irq-dqm-mask		= <0x00400000 0x00200000 0x00100000>;
			lwm-irq-mask-offset	= <0x1cb0 0x1d40 0x1dd8>;
			lwm-irq-status-offset	= <0x1ca0 0x1d30 0x1dc8>;
			ne-irq-mask-offset	= <0x1c5c 0x1cd4 0x1d68>;
			ne-irq-status-offset	= <0x1c18 0x1cc4 0x1d58>;
			ne-status-offset	= <0x1c20 0x1cc8 0x1d5c>;
			hwm-irq-mask-offset	= <0x1c88 0x1d1c 0x1db0>;
			hwm-irq-status-offset	= <0x1c78 0x1d0c 0x1da0>;
			tmr-irq-mask-offset	= <0x1c48 0x1cf8 0x1d8c>;
			tmr-irq-status-offset	= <0x1c38 0x1ce8 0x1d7c>;
		};

		dqmintc1: dqmintc1 {
			interrupts = <0 129 0>;
			interrupt-controller;
			#interrupt-cells = <1>;
			interrupt-parent = <0x1>;
			l1-irq-mask-offset	= <0x0058>;
			l1-irq-status-offset	= <0x005c>;
			l1-irq-dqm-mask		= <0x00400000 0x00200000 0x00100000>;
			lwm-irq-mask-offset	= <0x1cb4 0x1d44 0x1ddc>;
			lwm-irq-status-offset	= <0x1ca0 0x1d30 0x1dc8>;
			ne-irq-mask-offset	= <0x1c60 0x1cd8 0x1d6c>;
			ne-irq-status-offset	= <0x1c18 0x1cc4 0x1d58>;
			ne-status-offset	= <0x1c20 0x1cc8 0x1d5c>;
			hwm-irq-mask-offset	= <0x1c8c 0x1d20 0x1db4>;
			hwm-irq-status-offset	= <0x1c78 0x1d0c 0x1da0>;
			tmr-irq-mask-offset	= <0x1c4c 0x1cfc 0x1d90>;
			tmr-irq-status-offset	= <0x1c38 0x1ce8 0x1d7c>;
		};

		dqm2: dqm2 {
			qname = "RPC RG-->CM";
			id = <2>;
			words = <4>;
			depth = <8>;
			lwm = <2>;
			hwm = <1>;
			interrupt-parent = <&dqmintc0>;
			interrupts = <2>;
		};
		dqm3: dqm3 {
			qname = "RPC RG<--CM";
			id = <3>;
			words = <4>;
			depth = <8>;
			lwm = <2>;
			hwm = <1>;
			interrupt-parent = <&dqmintc0>;
			interrupts = <3>;
		};
		dqm14: dqm14 {
			qname = "Private Network RG-->CM";
			id = <14>;
			words = <2>;
			depth = <16>;
			lwm = <4>;
			hwm = <1>;
			interrupt-parent = <&dqmintc0>;
			interrupts = <14>;
		};
		dqm15: dqm15 {
			qname = "Private Network RG<--CM";
			id = <15>;
			words = <2>;
			depth = <64>;
			lwm = <4>;
			hwm = <1>;
			interrupt-parent = <&dqmintc0>;
			interrupts = <15>;
		};
		dqm20: dqm20 {
			qname = "RPC SVM-->CM";
			id = <20>;
			words = <4>;
			depth = <8>;
			lwm = <2>;
			hwm = <1>;
			interrupt-parent = <&dqmintc0>;
			interrupts = <20>;
		};
		dqm21: dqm21 {
			qname = "RPC SVM<--CM";
			id = <21>;
			words = <4>;
			depth = <8>;
			lwm = <2>;
			hwm = <1>;
			interrupt-parent = <&dqmintc0>;
			interrupts = <21>;
		};
		dqm32: dqm32 {
			qname = "RG DS Forward (RG-->Runner)";
			id = <32>;
			words = <4>;
			depth = <64>;
			lwm = <16>;
			hwm = <1>;
			interrupt-parent = <&dqmintc1>;
			interrupts = <32>;
		};
		dqm34: dqm34 {
			qname = "RG DS Egress (RG-->Runner)";
			id = <34>;
			words = <4>;
			depth = <64>;
			lwm = <16>;
			hwm = <1>;
			interrupt-parent = <&dqmintc1>;
			interrupts = <34>;
		};
		dqm35: dqm35 {
			qname = "RG US Egress (RG-->Runner)";
			id = <35>;
			words = <4>;
			depth = <64>;
			lwm = <16>;
			hwm = <1>;
			interrupt-parent = <&dqmintc1>;
			interrupts = <35>;
		};
		dqm47: dqm47 {
			qname = "SKB Prealloc (RG-->Runner)";
			id = <47>;
			words = <2>;
			depth = <4000>;
			lwm = <512>;
			hwm = <1>;
			interrupt-parent = <&dqmintc1>;
			interrupts = <47>;
		};
		dqm48: dqm48 {
			qname = "RG Exception LAN (Runner-->RG)";
			id = <48>;
			words = <4>;
			depth = <4000>;
			lwm = <64>;
			hwm = <64>;
			timeout = <1000>;
			interrupt-parent = <&dqmintc1>;
			interrupts = <48>;
		};
		dqm49: dqm49 {
			qname = "RG Exception Ctl (Runner-->RG)";
			id = <49>;
			words = <4>;
			depth = <256>;
			lwm = <64>;
			hwm = <1>;
			interrupt-parent = <&dqmintc1>;
			interrupts = <49>;
		};
		dqm50: dqm50 {
			qname = "RG Exception WAN (Runner-->RG)";
			id = <50>;
			words = <4>;
			depth = <4000>;
			lwm = <64>;
			hwm = <64>;
			timeout = <1000>;
			interrupt-parent = <&dqmintc1>;
			interrupts = <50>;
		};
		dqm51: dqm51 {
			qname = "RG Expected 0    (Runner-->RG)";
			id = <51>;
			words = <4>;
			depth = <4000>;
			lwm = <64>;
			hwm = <64>;
			timeout = <1000>;
			interrupt-parent = <&dqmintc1>;
			interrupts = <51>;
		};
		dqm52: dqm52 {
			qname = "RG Expected 1    (Runner-->RG)";
			id = <52>;
			words = <4>;
			depth = <4000>;
			lwm = <64>;
			hwm = <64>;
			timeout = <1000>;
			interrupt-parent = <&dqmintc1>;
			interrupts = <52>;
		};
		dqm53: dqm53 {
			qname = "RG Expected 2    (Runner-->RG)";
			id = <53>;
			words = <4>;
			depth = <4000>;
			lwm = <64>;
			hwm = <64>;
			timeout = <1000>;
			interrupt-parent = <&dqmintc1>;
			interrupts = <53>;
		};
		dqm54: dqm54 {
			qname = "RG Expected 3    (Runner-->RG)";
			id = <54>;
			words = <4>;
			depth = <4000>;
			lwm = <64>;
			hwm = <64>;
			timeout = <1000>;
			interrupt-parent = <&dqmintc1>;
			interrupts = <54>;
		};
		dqm55: dqm55 {
			qname = "RG Expected 0    (Runner-->RG)";
			id = <55>;
			words = <1>;
			depth = <4000>;
			lwm = <16>;
			hwm = <1000>;
			interrupt-parent = <&dqmintc1>;
			interrupts = <55>;
		};
	};

Live IRQ example:

	dqmlive: dqmlive@0xd1201c00 {
		compatible = "brcm,dqm";
		reg = <0x0 0xd1200000 0x0 0x4400>,<0x0 0xd1205000 0x0 0x5400>;

		dev-name = "dfap";
		cfg-offset		= <0x1c00>;
		q-ctl-base-offset	= <0x4000>;
		q-tmr-base-offset	= <0x2000>;
		q-data-base-offset	= <0x0000>;
		q-status-base-offset	= <0x2800>;
		q-mib-base-offset	= <0x3000>;
		q-count			= <32>;
		live-irq;
		dqm1: dqm1 {
			qname = "dfap0";
			id = <1>;
			interrupts = <0 128 0>;
		};
	};
