qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [PATCHv2 1/2] sun4m: Add Sun CG3 framebuffer and corres


From: Peter Crosthwaite
Subject: Re: [Qemu-devel] [PATCHv2 1/2] sun4m: Add Sun CG3 framebuffer and corresponding OpenBIOS FCode ROM
Date: Sat, 15 Feb 2014 00:54:05 +1000

On Sun, Feb 9, 2014 at 11:35 PM, Mark Cave-Ayland
<address@hidden> wrote:
> On 09/02/14 04:14, Peter Crosthwaite wrote:
>
> Hi Peter,
>
> Thanks for the review!
>
> (cut)
>
>
>>> +/* #define DEBUG_CG3 */
>>> +
>>> +#define CG3_ROM_FILE  "QEMU,cgthree.bin"
>>> +#define FCODE_MAX_ROM_SIZE 0x10000
>>> +
>>> +#define CG3_REG_SIZE  0x20
>>> +#define CG3_VRAM_SIZE 0x100000
>>> +#define CG3_VRAM_OFFSET 0x800000
>>> +
>>> +#ifdef DEBUG_CG3
>>> +#define DPRINTF(fmt, ...)                                       \
>>> +    printf("CG3: " fmt , ## __VA_ARGS__)
>>> +#else
>>> +#define DPRINTF(fmt, ...)
>>> +#endif
>>> +
>>
>>
>> With debug macros its better to use a regular if. Something like:
>>
>> #ifndef DEBUG_CG3
>> #define DEBUG_CG3 0
>> #endif
>>
>> #define DPRINTF(...) do { \
>>    if (DEBUG_CG3) { \
>>      printf(...) \
>>    } \
>> } while (0);
>>
>> The reason being your debug code will always be compile checked
>> allowing contributors to apply type changes without breaking your
>> debug code accidently.
>
>
> Yes, I can see how this would be a good idea and will change it for the next
> version. The reason it is done like this is because where possible I've
> tried to copy the style of the existing TCX driver so that someone familiar
> with one driver can easily work on the other.
>
> (cut)
>
>
>>> +static uint64_t cg3_reg_read(void *opaque, hwaddr addr, unsigned size)
>>> +{
>>> +    CG3State *s = opaque;
>>> +    int val;
>>> +
>>> +    switch (addr) {
>>> +    case 0x10:
>>
>>
>> What are these magic numbers? You should define macros matching the
>> names in your register specs.
>>
>>> +        val = s->regs[0];
>>
>>
>> Same for these hardcoded indicies into regs[].
>
>
> The short answer is "we don't know" because we don't have any documentation.

Sigh.... This has happened quite a lot lately.

If the kernel driver has macros, re-use them as much as possible. If
you have a vague idea on whats, what, a few well invented names would
help the device self-documentation.

> If you compare with the TCX driver, you'll see that it uses numbered
> constants in exactly the same way, for exactly the same reason. Few
> developers are willing to enter into an NDA to get the documentation, even
> Sun doesn't have all of it, and since Oracle took over they have removed the
> few bits that they could find.
>
> So the TCX and the cg3 drivers are generally realised by looking at source
> code from the various OSs and then coming up with something that works.
>
>
>>> +        break;
>>> +    case 0x11:
>>> +        val = s->regs[1] | 0x71; /* monitor ID 7, board type = 1 (color)
>>> */
>>> +        break;
>>> +    case 0x12 ... 0x1f:
>>> +        val = s->regs[addr - 0x10];
>>> +        break;
>>> +    default:
>>> +        val = 0;
>>> +        break;
>>
>>
>> Is this guest error or unimplemented behaviour? You should
>> qemu_log_mask( accordingly.
>
>
> Again "we don't know", but it seems to work.
>

With no-spec devices, we have been encoraging use of qemu_log_mask(LOG_UNIMP

>
>>> +    }
>>> +    DPRINTF("read %02x from reg %x\n", val, (int)addr);
>>> +    return val;
>>> +}
>>> +
>>> +static void cg3_reg_write(void *opaque, hwaddr addr, uint64_t val,
>>> +                          unsigned size)
>>> +{
>>> +    CG3State *s = opaque;
>>> +    uint8_t regval;
>>> +    int i;
>>> +
>>> +    DPRINTF("write %02lx to reg %x size %d\n", val, (int)addr, size);
>>> +
>>> +    switch (addr) {
>>> +    case 0:
>>> +        s->dac_index = val;
>>> +        s->dac_state = 0;
>>> +        break;
>>> +    case 4:
>>> +        /* This register can be written to as either a long word or a
>>> byte.
>>> +         * According to the SBus specification, byte transfers are
>>> placed
>>> +         * in bits 31-28 */
>>
>>
>> Very strange. Is it not just a case of generic big-endian accessible
>> rather than just such a very specific exception here?
>
>
> This is an interesting area. Some of the sun4m peripherals are not connected
> directly to the CPU MBus but to an external SBus accessible over the
> processor physical address lines.
>
> Generally all SBus access is done using 4-byte accesses for efficiency,
> however probably due to the age of this driver, Solaris insists on using
> single byte transfers for the cg3 DAC registers which get converted by the
> SBus to 4-byte access but with the byte in the MSB.
>
> So far this is the only driver we've found that tries to access the bus in
> this way, and it would be a large project to switch sun4m from sysbus over
> to something else. Hence I've added and documented the workaround in this
> fashion.
>
>>> +        if (size == 1) {
>>> +            val<<= 24;
>>> +        }
>>> +
>>> +        for (i = 0; i<  size; i++) {
>>> +            regval = val>>  24;
>>> +
>>> +            switch (s->dac_state) {
>>> +            case 0:
>>> +                s->r[s->dac_index] = regval;
>>> +                s->dac_state++;
>>> +                break;
>>> +            case 1:
>>> +                s->g[s->dac_index] = regval;
>>> +                s->dac_state++;
>>> +                break;
>>> +            case 2:
>>> +                s->b[s->dac_index] = regval;
>>> +                /* Index autoincrement */
>>> +                s->dac_index = (s->dac_index + 1)&  255;
>>>
>>> +            default:
>>> +                s->dac_state = 0;
>>> +                break;
>>> +            }
>>> +            val<<= 8;
>>> +        }
>>> +        s->full_update = 1;
>>> +        break;
>>> +    case 0x10:
>>> +        s->regs[0] = val;
>>> +        break;
>>> +    case 0x11:
>>> +        if (s->regs[1]&  0x80) {
>>
>>
>> Define macros for register field bits.
>
>
> While we don't know the official name for this, I could invent one for this
> particular case if required?
>
>
>>> +            /* clear interrupt */
>>> +            s->regs[1]&= ~0x80;
>>> +            qemu_irq_lower(s->irq);
>>> +        }
>>> +        break;
>>> +    case 0x12 ... 0x1f:
>>> +        s->regs[addr - 0x10] = val;
>>> +        break;
>>> +    default:
>>> +        break;
>>> +    }
>>> +}
>>> +
>>> +static const MemoryRegionOps cg3_reg_ops = {
>>> +    .read = cg3_reg_read,
>>> +    .write = cg3_reg_write,
>>> +    .endianness = DEVICE_NATIVE_ENDIAN,
>>> +    .valid = {
>>> +        .min_access_size = 1,
>>> +        .max_access_size = 4,
>>
>>
>> Your hander switch statements stride in 4, are you only doing this for
>> your one exception case of that one-byte big-endian access I commented
>> earlier.
>
>
> Yes, that is correct.
>

Should you trap misaligned accesses then?

Regards,
Peter

>
>>> +    },
>>> +};
>>> +
>>> +static const GraphicHwOps cg3_ops = {
>>> +    .invalidate = cg3_invalidate_display,
>>> +    .gfx_update = cg3_update_display,
>>> +};
>>> +
>>> +static int cg3_init1(SysBusDevice *dev)
>>
>>
>> Use of SysBusDevice::init functions is depracated. Please use object
>> init fns or Device::Realize functions instead.
>
>
> Right. As I mentioned earlier in the email, I tried to base the CG3 driver
> on the existing TCX driver to keep things similar. Does it make sense to
> switch this patch over to use object init functions while TCX doesn't?
>
> Also can the object init fns (I guess this is QOM?) still make use of
> sysbus?
>
>
> Many thanks,
>
> Mark.
>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]