github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/soc/bcm2835/framebuffer/framebuffer.go (about)

     1  // BCM2835 SoC FrameBuffer support
     2  // https://github.com/usbarmory/tamago
     3  //
     4  // Copyright (c) the bcm2835 package authors
     5  //
     6  // Use of this source code is governed by the license
     7  // that can be found in the LICENSE file.
     8  
     9  package framebuffer
    10  
    11  import (
    12  	"encoding/binary"
    13  	"fmt"
    14  
    15  	"github.com/usbarmory/tamago/soc/bcm2835"
    16  )
    17  
    18  // EDID gets the raw EDID information from the attached monitor
    19  func EDID() []byte {
    20  	outBuf := []byte{}
    21  
    22  	for block := uint32(0); true; block++ {
    23  		buf := make([]byte, bcm2835.VC_MEM_GET_EDID_BLOCK_LEN)
    24  		binary.LittleEndian.PutUint32(buf[0:], block)
    25  
    26  		msg := &bcm2835.MailboxMessage{
    27  			Tags: []bcm2835.MailboxTag{
    28  				{
    29  					ID:     bcm2835.VC_MEM_GET_EDID_BLOCK,
    30  					Buffer: buf,
    31  				},
    32  			},
    33  		}
    34  
    35  		bcm2835.Mailbox.Call(bcm2835.VC_CH_PROPERTYTAGS_A_TO_VC, msg)
    36  
    37  		tag := msg.Tag(bcm2835.VC_MEM_GET_EDID_BLOCK)
    38  
    39  		if tag == nil || len(tag.Buffer) < 8 {
    40  			return outBuf
    41  		}
    42  
    43  		if binary.LittleEndian.Uint32(tag.Buffer[0:]) != block {
    44  			panic("Got EDID data for wrong block")
    45  		}
    46  
    47  		status := binary.LittleEndian.Uint32(tag.Buffer[4:])
    48  		if status != 0 {
    49  			break
    50  		}
    51  
    52  		outBuf = append(outBuf, tag.Buffer[8:]...)
    53  	}
    54  
    55  	return outBuf
    56  }
    57  
    58  // PhysicalSize is the dimensions of the current framebuffer in pixels
    59  func PhysicalSize() (width uint32, height uint32) {
    60  	buf := make([]byte, bcm2835.VC_FB_GET_PHYSICAL_SIZE_LEN)
    61  
    62  	msg := &bcm2835.MailboxMessage{
    63  		Tags: []bcm2835.MailboxTag{
    64  			{
    65  				ID:     bcm2835.VC_FB_GET_PHYSICAL_SIZE,
    66  				Buffer: buf,
    67  			},
    68  		},
    69  	}
    70  
    71  	bcm2835.Mailbox.Call(bcm2835.VC_CH_PROPERTYTAGS_A_TO_VC, msg)
    72  
    73  	tag := msg.Tag(bcm2835.VC_FB_GET_PHYSICAL_SIZE)
    74  
    75  	if tag == nil || len(tag.Buffer) < 8 {
    76  		return 0, 0
    77  	}
    78  
    79  	return binary.LittleEndian.Uint32(tag.Buffer[0:]), binary.LittleEndian.Uint32(tag.Buffer[4:])
    80  }
    81  
    82  // SetPhysicalSize changes the display resolution (in pixels)
    83  func SetPhysicalSize(width uint32, height uint32) error {
    84  	buf := make([]byte, bcm2835.VC_FB_SET_PHYSICAL_SIZE_LEN)
    85  	binary.LittleEndian.PutUint32(buf[0:], width)
    86  	binary.LittleEndian.PutUint32(buf[4:], height)
    87  
    88  	msg := &bcm2835.MailboxMessage{
    89  		Tags: []bcm2835.MailboxTag{
    90  			{
    91  				ID:     bcm2835.VC_FB_SET_PHYSICAL_SIZE,
    92  				Buffer: buf,
    93  			},
    94  		},
    95  	}
    96  
    97  	bcm2835.Mailbox.Call(bcm2835.VC_CH_PROPERTYTAGS_A_TO_VC, msg)
    98  
    99  	tag := msg.Tag(bcm2835.VC_FB_SET_PHYSICAL_SIZE)
   100  
   101  	if tag == nil || len(tag.Buffer) < 8 {
   102  		return fmt.Errorf("failed to set desired size")
   103  	}
   104  
   105  	newWidth := binary.LittleEndian.Uint32(tag.Buffer[0:])
   106  	newHeight := binary.LittleEndian.Uint32(tag.Buffer[4:])
   107  
   108  	if newWidth != width || newHeight != height {
   109  		return fmt.Errorf("failed to set desired size")
   110  	}
   111  
   112  	return nil
   113  }